bitkeeper revision 1.1403 (4284c2edzLTGTr4gHmGzYsZMuetTRQ)
authormjw@wray-m-3.hpl.hp.com <mjw@wray-m-3.hpl.hp.com>
Fri, 13 May 2005 15:08:29 +0000 (15:08 +0000)
committermjw@wray-m-3.hpl.hp.com <mjw@wray-m-3.hpl.hp.com>
Fri, 13 May 2005 15:08:29 +0000 (15:08 +0000)
Switch to using unix-domain interface on xend instead
of http via libcurl.
Sundry other merges and fixes.
Signed-off-by: Mike Wray <mike.wray@hp.com>
18 files changed:
.rootkeys
tools/libxutil/fd_stream.c [new file with mode: 0644]
tools/libxutil/fd_stream.h [new file with mode: 0644]
tools/libxutil/lexis.h
tools/libxutil/sxpr.c
tools/libxutil/sxpr.h
tools/libxutil/sxpr_parser.c
tools/libxutil/sxpr_parser.h
tools/libxutil/sys_string.c
tools/libxutil/sys_string.h
tools/python/xen/xend/server/SrvDaemon.py
tools/python/xen/xend/server/event.py
tools/xfrd/Make.xfrd
tools/xfrd/Makefile
tools/xfrd/connection.c
tools/xfrd/lzi_stream.c
tools/xfrd/xen_domain.c
tools/xfrd/xfrd.c

index df709f294d2544957eb53236407f71e8d5b8bf78..b70a81dd5004e8951579917189b5f3e61ced74f4 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 41a216cav5JJbtDQnusfuMa_1x_Xpw tools/libxutil/debug.h
 40e9808eyjiahG5uF6AMelNVujBzCg tools/libxutil/enum.c
 40e9808eZpbdn9q2KSSMGCNvY_ZgpQ tools/libxutil/enum.h
+4284c2ecWyadIhHF1u_QSgWqIXkaLA tools/libxutil/fd_stream.c
+4284c2ecEOOcF6fZUf_NsZzYAoNo-w tools/libxutil/fd_stream.h
 40e03332p5Dc_owJQRuN72ymJZddFQ tools/libxutil/file_stream.c
 40e03332jWfB2viAhLSkq1WK0r_iDQ tools/libxutil/file_stream.h
 40e03332rUjNMGg11n2rN6V4DCrvOg tools/libxutil/gzip_stream.c
diff --git a/tools/libxutil/fd_stream.c b/tools/libxutil/fd_stream.c
new file mode 100644 (file)
index 0000000..428f0a5
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/** @file
+ * An IOStream implementation using fds.
+ */
+#ifndef __KERNEL__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include "allocate.h"
+#include "fd_stream.h"
+
+#define MODULE_NAME "fd_stream"
+#define DEBUG 1
+//#undef DEBUG
+#include "debug.h"
+
+static int fd_read(IOStream *s, void *buf, size_t n);
+static int fd_write(IOStream *s, const void *buf, size_t n);
+static int fd_error(IOStream *s);
+static int fd_close(IOStream *s);
+static void fd_free(IOStream *s);
+static int fd_flush(IOStream *s);
+
+/** Methods used by a fd IOStream. */
+static const IOMethods fd_methods = {
+    read:  fd_read,
+    write: fd_write,
+    error: fd_error,
+    close: fd_close,
+    free:  fd_free,
+    flush: fd_flush,
+};
+
+/** Get the fd data.
+ * 
+ * @param io fd stream
+ * @return data
+ */
+static inline FDData * fd_data(IOStream *io){
+    return (FDData *)io->data;
+}
+
+/** Test if a stream is a fd stream.
+ *
+ * @param io stream
+ * @return 0 if a fd stream, -EINVAL if not
+ */
+int fd_stream_check(IOStream *io){
+    return (io && io->methods == &fd_methods ? 0 : -EINVAL);
+}
+
+/** Get the data for a fd stream.
+ *
+ * @param io stream
+ * @param data return value for the data
+ * @return 0 if a fd stream, -EINVAL if not
+ */
+int fd_stream_data(IOStream *io, FDData **data){
+    int err = fd_stream_check(io);
+    if(err){
+        *data = NULL;
+    } else {
+        *data = fd_data(io);
+    }
+    return err;
+}
+
+
+/** Write to the underlying fd.
+ *
+ * @param stream input
+ * @param buf where to put input
+ * @param n number of bytes to write
+ * @return number of bytes written
+ */
+static int fd_write(IOStream *s, const void *buf, size_t n){
+    FDData *data = fd_data(s);
+    int k;
+    k = write(data->fd, buf, n);
+    return k;
+}
+
+/** Read from the underlying stream;
+ *
+ * @param stream input
+ * @param buf where to put input
+ * @param n number of bytes to read
+ * @return number of bytes read
+ */
+static int fd_read(IOStream *s, void *buf, size_t n){
+    FDData *data = fd_data(s);
+    int k;
+    k = read(data->fd, buf, n);
+    //printf("> fd_read> buf=%p n=%d --> k=%d\n", buf, n, k);
+    return k;
+}
+
+/** Flush the fd (no-op).
+ *
+ * @param s fd stream
+ * @return 0 on success, error code otherwise
+ */
+static int fd_flush(IOStream *s){
+    return 0;
+}
+
+/** Check if a fd stream has an error (no-op).
+ *
+ * @param s fd stream
+ * @return 1 if has an error, 0 otherwise
+ */
+static int fd_error(IOStream *s){
+    return 0;
+}
+
+/** Close a fd stream.
+ *
+ * @param s fd stream to close
+ * @return result of the close
+ */
+static int fd_close(IOStream *s){
+    FDData *data = fd_data(s);
+    return close(data->fd);
+}
+
+/** Free a fd stream.
+ *
+ * @param s fd stream
+ */
+static void fd_free(IOStream *s){
+    FDData *data = fd_data(s);
+    deallocate(data);
+}
+
+/** Create an IOStream for a fd.
+ *
+ * @param fd fd to wtap
+ * @return new IOStream using fd for i/o
+ */
+IOStream *fd_stream_new(int fd){
+    int err = -ENOMEM;
+    IOStream *io = NULL;
+    FDData *data = NULL;
+
+    io = ALLOCATE(IOStream);
+    if(!io) goto exit;
+    io->methods = &fd_methods;
+    data = ALLOCATE(FDData);
+    if(!data) goto exit;
+    io->data = data;
+    data->fd = fd;
+    err = 0;
+  exit:
+    if(err){
+        if(io){
+            if(data) deallocate(data);
+            deallocate(io);
+            io = NULL;
+        }
+    }
+    return io;
+}
+
+#endif
diff --git a/tools/libxutil/fd_stream.h b/tools/libxutil/fd_stream.h
new file mode 100644 (file)
index 0000000..b37a686
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _XMC_FD_STREAM_H_
+#define _XMC_FD_STREAM_H_
+
+#ifndef __KERNEL__
+#include "iostream.h"
+
+/** Data associated with a fd stream. */
+typedef struct FDData {
+    /** The socket file descriptor. */
+    int fd;
+} FDData;
+
+extern IOStream *fd_stream_new(int fd);
+extern int fd_stream_data(IOStream *io, FDData **data);
+extern int fd_stream_check(IOStream *io);
+
+#endif
+#endif /* !_XMC_FD_STREAM_H_ */
index be8fb653d37d3c881ff75b3859dc739728f91f73..d49a3547d676d282c31b16792481bb20b9107e23 100644 (file)
@@ -34,7 +34,7 @@
 #define space_class ((char []){ '\n', '\r', '\t', ' ', '\f' , 0 })
 
 /** Class of separator characters. */
-#define sep_class "{}()<>[]@!;"
+#define sep_class "{}()<>[]!;\"'"
 
 #define comment_class "#"
 
index 02a5040b52aa117f2f162ecb5a2678734eba7436..d264527f25759679817a05c9155b7015ad11f948 100644 (file)
 #include <errno.h>
 #endif
 
+#ifdef __KERNEL__
+#include <linux/random.h>
+
+int rand(void){
+    int v;
+    get_random_bytes(&v, sizeof(v));
+    return v;
+}
+
+#else
+#include <stdlib.h>
+#endif
+
 #undef free
 
 /** @file
 static int atom_print(IOStream *io, Sxpr obj, unsigned flags);
 static int atom_equal(Sxpr x, Sxpr y);
 static void atom_free(Sxpr obj);
+static Sxpr atom_copy(Sxpr obj);
 
 static int string_print(IOStream *io, Sxpr obj, unsigned flags);
 static int string_equal(Sxpr x, Sxpr y);
 static void string_free(Sxpr obj);
+static Sxpr string_copy(Sxpr obj);
 
 static int cons_print(IOStream *io, Sxpr obj, unsigned flags);
 static int cons_equal(Sxpr x, Sxpr y);
 static void cons_free(Sxpr obj);
+static Sxpr cons_copy(Sxpr obj);
 
 static int null_print(IOStream *io, Sxpr obj, unsigned flags);
 static int none_print(IOStream *io, Sxpr obj, unsigned flags);
 static int int_print(IOStream *io, Sxpr obj, unsigned flags);
 static int bool_print(IOStream *io, Sxpr obj, unsigned flags);
+static int err_print(IOStream *io, Sxpr obj, unsigned flags);
+static int nomem_print(IOStream *io, Sxpr obj, unsigned flags);
 
 /** Type definitions. */
 static SxprType types[1024] = {
-    [T_NONE]     { type:    T_NONE,     name: "none",       print: none_print      },
-    [T_NULL]     { type:    T_NULL,     name: "null",       print: null_print      },
-    [T_UINT]     { type:    T_UINT,     name: "int",        print: int_print,      },
-    [T_BOOL]     { type:    T_BOOL,     name: "bool",       print: bool_print,     },
-    [T_ATOM]     { type:    T_ATOM,     name: "atom",       print: atom_print,
-                  pointer: TRUE,
-                  free:    atom_free,
-                  equal:   atom_equal,
-                },
-    [T_STRING]   { type:    T_STRING,   name: "string",     print: string_print,
-                  pointer: TRUE,
-                  free:    string_free,
-                  equal:   string_equal,
-                },
-    [T_CONS]     { type:    T_CONS,     name: "cons",       print: cons_print,
-                  pointer: TRUE,
-                  free:    cons_free,
-                  equal:   cons_equal,
-                },
+    [T_NONE]     { .type=    T_NONE,     .name= "none",       .print= none_print      },
+    [T_NULL]     { .type=    T_NULL,     .name= "null",       .print= null_print      },
+    [T_UINT]     { .type=    T_UINT,     .name= "int",        .print= int_print,      },
+    [T_BOOL]     { .type=    T_BOOL,     .name= "bool",       .print= bool_print,     },
+    [T_ERR]      { .type=    T_ERR,      .name= "err",        .print= err_print,      },
+    [T_NOMEM]    { .type=    T_ERR,      .name= "nomem",      .print= nomem_print,    },
+    [T_ATOM]     { .type=    T_ATOM,     .name= "atom",       .print= atom_print,
+                   .pointer= TRUE,
+                   .free=    atom_free,
+                   .equal=   atom_equal,
+                   .copy=    atom_copy,
+                 },
+    [T_STRING]   { .type=    T_STRING,   .name= "string",     .print= string_print,
+                   .pointer= TRUE,
+                   .free=    string_free,
+                   .equal=   string_equal,
+                   .copy=    string_copy,
+                 },
+    [T_CONS]     { .type=    T_CONS,     .name= "cons",       .print= cons_print,
+                   .pointer= TRUE,
+                   .free=    cons_free,
+                   .equal=   cons_equal,
+                   .copy=    cons_copy,
+                 },
 };
 
 /** Number of entries in the types array. */
@@ -157,12 +180,29 @@ int objprint(IOStream *io, Sxpr x, unsigned flags){
     int k = 0;
     if(!io) return k;
     if(flags & PRINT_TYPE){
-       k += IOStream_print(io, "%s:", def->name);
+        k += IOStream_print(io, "%s:", def->name);
+    }
+    if(def->pointer && (flags & PRINT_ADDR)){
+        k += IOStream_print(io, "<%p>", get_ptr(x));
     }
     k += print_fn(io, x, flags);
     return k;
 }
 
+Sxpr objcopy(Sxpr x){
+    SxprType *def = get_sxpr_type(get_type(x));
+    ObjCopyFn *copy_fn = (def ? def->copy : NULL);
+    Sxpr v;
+    if(copy_fn){
+        v = copy_fn(x);
+    } else if(def->pointer){
+        v = ONOMEM;
+    } else {
+        v = x;
+    }
+    return v;
+}
+
 /** General sxpr free function.
  * Frees an sxpr using the free function for its type.
  * Free functions must recursively free any subsxprs.
@@ -176,11 +216,11 @@ void objfree(Sxpr x){
     SxprType *def = get_sxpr_type(get_type(x));
 
     if(def){
-       if(def->free){
-           def->free(x);
-       } else if (def->pointer){
-           hfree(x);
-       }
+        if(def->free){
+            def->free(x);
+        } else if (def->pointer){
+            hfree(x);
+        }
     }
 }
 
@@ -284,9 +324,9 @@ Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){
  */
 int cons_subset(Sxpr s, Sxpr t){
     for( ; CONSP(t); t = CDR(t)){
-       if(!CONSP(cons_member(s, CAR(t)))){
-           return 0;
-       }
+        if(!CONSP(cons_member(s, CAR(t)))){
+            return 0;
+        }
     }
     return 1;
 }
@@ -365,18 +405,27 @@ Sxpr setf(Sxpr k, Sxpr v, Sxpr l){
 #endif /* USE_GC */
 
 /** Create a new atom with the given name.
+ * Makes an integer sxpr if the name can be parsed as an int.
  *
  * @param name the name
  * @return new atom
  */
 Sxpr atom_new(char *name){
     Sxpr n, obj = ONOMEM;
+    long v;
 
-    n = string_new(name);
-    if(NOMEMP(n)) goto exit;
-    obj = HALLOC(ObjAtom, T_ATOM);
-    if(NOMEMP(obj)) goto exit;
-    OBJ_ATOM(obj)->name = n;
+    if(convert_atol(name, &v) == 0){
+        obj = OINT(v);
+    } else {
+        n = string_new(name);
+        if(NOMEMP(n)) goto exit;
+        obj = HALLOC(ObjAtom, T_ATOM);
+        if(NOMEMP(obj)){
+            string_free(n);
+            goto exit;
+        }
+        OBJ_ATOM(obj)->name = n;
+    }
   exit:
     return obj;
 }
@@ -392,6 +441,20 @@ void atom_free(Sxpr obj){
     hfree(obj);
 }
 
+/** Copy an atom.
+ *
+ * @param obj to copy
+ */
+Sxpr atom_copy(Sxpr obj){
+    Sxpr v;
+    if(OBJ_ATOM(obj)->interned){
+        v = obj;
+    } else {
+        v = atom_new(atom_name(obj));
+    }
+    return v;
+}
+
 /** Print an atom. Prints the atom name.
  *
  * @param io stream to print to
@@ -400,8 +463,7 @@ void atom_free(Sxpr obj){
  * @return number of bytes printed
  */
 int atom_print(IOStream *io, Sxpr obj, unsigned flags){
-    //return string_print(io, OBJ_ATOM(obj)->name, (flags | PRINT_RAW));
-    return string_print(io, OBJ_ATOM(obj)->name, flags);
+    return objprint(io, OBJ_ATOM(obj)->name, flags);
 }
 
 /** Atom equality.
@@ -430,13 +492,17 @@ char * atom_name(Sxpr obj){
     return string_string(OBJ_ATOM(obj)->name);
 }
 
+int atom_length(Sxpr obj){
+    return string_length(OBJ_ATOM(obj)->name);
+}
+
 /** Get the C string from a string sxpr.
  *
  * @param obj string sxpr
  * @return string
  */
 char * string_string(Sxpr obj){
-    return OBJ_STRING(obj);
+    return OBJ_STRING(obj)->data;
 }
 
 /** Get the length of a string.
@@ -445,7 +511,7 @@ char * string_string(Sxpr obj){
  * @return length
  */
 int string_length(Sxpr obj){
-    return strlen(OBJ_STRING(obj));
+    return OBJ_STRING(obj)->len;
 }
 
 /** Create a new string. The input string is copied,
@@ -456,12 +522,28 @@ int string_length(Sxpr obj){
  */
 Sxpr string_new(char *s){
     int n = (s ? strlen(s) : 0);
+    return string_new_n(s, n);
+}
+
+/** Create a new string. The input string is copied,
+ * and need not be null-terminated.
+ *
+ * @param s characters to put in the string (may be null)
+ * @param n string length
+ * @return new sxpr
+ */
+Sxpr string_new_n(char *s, int n){
     Sxpr obj;
-    obj = halloc(n+1, T_STRING);
+    obj = halloc(sizeof(ObjString) + n + 1, T_STRING);
     if(!NOMEMP(obj)){
-        char *str = OBJ_STRING(obj);
-        strncpy(str, s, n);
-        str[n] = '\0';
+        char *str = OBJ_STRING(obj)->data;
+        OBJ_STRING(obj)->len = n;
+        if(s){
+            memcpy(str, s, n);
+            str[n] = '\0';
+        } else {
+            memset(str, 0, n + 1);
+        }
     }
     return obj;
 }
@@ -474,70 +556,180 @@ void string_free(Sxpr obj){
     hfree(obj);
 }
 
+/** Copy a string.
+ *
+ * @param obj to copy
+ */
+Sxpr string_copy(Sxpr obj){
+    return string_new_n(string_string(obj), string_length(obj));
+}
+
 /** Determine if a string needs escapes when printed
  * using the given flags.
  *
  * @param str string to check
+ * @param n string length
  * @param flags print flags
  * @return 1 if needs escapes, 0 otherwise
  */
-int needs_escapes(char *str, unsigned flags){
+int needs_escapes(char *str, int n, unsigned flags){
     char *c;
+    int i;
     int val = 0;
 
     if(str){
-       for(c=str; *c; c++){
-           if(in_alpha_class(*c)) continue;
-           if(in_decimal_digit_class(*c)) continue;
-           if(in_class(*c, "/._+:@~-")) continue;
-           val = 1;
-           break;
-       }
-    }
-    //printf("\n> val=%d str=|%s|\n", val, str);
+        for(i=0, c=str; i<n; i++, c++){
+            if(in_alpha_class(*c)) continue;
+            if(in_decimal_digit_class(*c)) continue;
+            if(in_class(*c, "/._+:@~-")) continue;
+            val = 1;
+            break;
+        }
+    }
     return val;
 }
 
+char randchar(void){
+    int r;
+    char c;
+    for( ; ; ){
+        r = rand();
+        c = (r >> 16) & 0xff;
+        if('a' <= c && c <= 'z') break;
+    }
+    return c;
+}
+
+int string_contains(char *s, int s_n, char *k, int k_n){
+    int i, n = s_n - k_n;
+    for(i=0; i < n; i++){
+        if(!memcmp(s+i, k, k_n)) return 1;
+    }
+    return 0;
+}
+
+int string_delim(char *s, int s_n, char *d, int d_n){
+    int i;
+    if(d_n < 4) return -1;
+    memset(d, 0, d_n+1);
+    for(i=0; i<3; i++){
+        d[i] = randchar();
+    }
+    for( ; i < d_n; i++){
+        if(!string_contains(s, s_n, d, i)){
+            return i;
+        }
+        d[i] = randchar();
+    }
+    return -1;
+}
+
+/** Print the bytes in a string as-is.
+ *
+ * @param io stream
+ * @param str string
+ * @param n length
+ * @return bytes written or error code
+ */
+int _string_print_raw(IOStream *io, char *str, int n){
+    int k = 0;
+    k = IOStream_write(io, str, n);
+    return k;
+}
+
+/** Print a string in counted data format.
+ *
+ * @param io stream
+ * @param str string
+ * @param n length
+ * @return bytes written or error code
+ */
+int _string_print_counted(IOStream *io, char *str, int n){
+    int k = 0;
+    k += IOStream_print(io, "%c%c%d%c",
+                        c_data_open, c_data_count, n, c_data_count);
+    k += IOStream_write(io, str, n);
+    return k;
+}
+  
+/** Print a string in quoted data format.
+ *
+ * @param io stream
+ * @param str string
+ * @param n length
+ * @return bytes written or error code
+ */
+int _string_print_quoted(IOStream *io, char *str, int n){
+    int k = 0;
+    char d[10];
+    int d_n;
+    d_n = string_delim(str, n, d, sizeof(d) - 1);
+    k += IOStream_print(io, "%c%c%s%c",
+                        c_data_open, c_data_quote, d, c_data_quote);
+    k += IOStream_write(io, str, n);
+    k += IOStream_print(io, "%c%s%c", c_data_quote, d, c_data_quote);
+    return k;
+}
+
+/** Print a string as a quoted string.
+ *
+ * @param io stream
+ * @param str string
+ * @param n length
+ * @return bytes written or error code
+ */
+int _string_print_string(IOStream *io, char *str, int n){
+    int k = 0;
+    
+    k += IOStream_print(io, "\"");
+    if(str){
+        char *s, *t;
+        for(s = str, t = str + n; s < t; s++){
+            if(*s < ' ' || *s >= 127 ){
+                switch(*s){
+                case '\a': k += IOStream_print(io, "\\a");  break;
+                case '\b': k += IOStream_print(io, "\\b");  break;
+                case '\f': k += IOStream_print(io, "\\f");  break;
+                case '\n': k += IOStream_print(io, "\\n");  break;
+                case '\r': k += IOStream_print(io, "\\r");  break;
+                case '\t': k += IOStream_print(io, "\\t");  break;
+                case '\v': k += IOStream_print(io, "\\v");  break;
+                default:
+                    // Octal escape;
+                    k += IOStream_print(io, "\\%o", *s);
+                    break;
+                }
+            } else if(*s == c_double_quote ||
+                      *s == c_single_quote ||
+                      *s == c_escape){
+                k += IOStream_print(io, "\\%c", *s);
+            } else {
+                k+= IOStream_print(io, "%c", *s);
+            }
+        }
+    }
+    k += IOStream_print(io, "\"");
+    return k;
+}
+
 /** Print a string to a stream, with escapes if necessary.
  *
  * @param io stream to print to
  * @param str string
+ * @param n string length
  * @param flags print flags
  * @return number of bytes written
  */
-int _string_print(IOStream *io, char *str, unsigned flags){
+int _string_print(IOStream *io, char *str, int n, unsigned flags){
     int k = 0;
-    if((flags & PRINT_RAW) || !needs_escapes(str, flags)){
-        k += IOStream_print(io, str);
+    if((flags & PRINT_COUNTED)){
+        k = _string_print_counted(io, str, n);
+    } else if((flags & PRINT_RAW) || !needs_escapes(str, n, flags)){
+        k = _string_print_raw(io, str, n);
+    } else if(n > 50){
+        k = _string_print_quoted(io, str, n);
     } else {
-       k += IOStream_print(io, "\"");
-       if(str){
-            char *s;
-            for(s = str; *s; s++){
-                if(*s < ' ' || *s >= 127 ){
-                    switch(*s){
-                    case '\a': k += IOStream_print(io, "\\a");  break;
-                    case '\b': k += IOStream_print(io, "\\b");  break;
-                    case '\f': k += IOStream_print(io, "\\f");  break;
-                    case '\n': k += IOStream_print(io, "\\n");  break;
-                    case '\r': k += IOStream_print(io, "\\r");  break;
-                    case '\t': k += IOStream_print(io, "\\t");  break;
-                    case '\v': k += IOStream_print(io, "\\v");  break;
-                    default:
-                        // Octal escape;
-                        k += IOStream_print(io, "\\%o", *s);
-                        break;
-                    }
-                } else if(*s == c_double_quote ||
-                          *s == c_single_quote ||
-                          *s == c_escape){
-                    k += IOStream_print(io, "\\%c", *s);
-                } else {
-                    k+= IOStream_print(io, "%c", *s);
-                }
-            }
-       }
-       k += IOStream_print(io, "\"");
+        k = _string_print_string(io, str, n);
     }
     return k;
 }
@@ -550,7 +742,14 @@ int _string_print(IOStream *io, char *str, unsigned flags){
  * @return number of bytes written
  */
 int string_print(IOStream *io, Sxpr obj, unsigned flags){
-    return _string_print(io, OBJ_STRING(obj), flags);
+    return _string_print(io,
+                         OBJ_STRING(obj)->data,
+                         OBJ_STRING(obj)->len,
+                         flags);
+}
+
+int string_eq(char *s, int s_n, char *t, int t_n){
+    return (s_n == t_n) && (memcmp(s, t, s_n) == 0);
 }
 
 /** Compare an sxpr with a string for equality.
@@ -563,9 +762,13 @@ int string_equal(Sxpr x, Sxpr y){
     int ok = 0;
     ok = eq(x,y);
     if(ok) goto exit;
-    ok = has_type(y, T_STRING) && !strcmp(OBJ_STRING(x), OBJ_STRING(y));
+    ok = has_type(y, T_STRING) &&
+        string_eq(OBJ_STRING(x)->data, OBJ_STRING(x)->len,
+                  OBJ_STRING(y)->data, OBJ_STRING(y)->len);
     if(ok) goto exit;
-    ok = has_type(y, T_ATOM) && !strcmp(OBJ_STRING(x), atom_name(y));
+    ok = has_type(y, T_ATOM) &&
+        string_eq(OBJ_STRING(x)->data, OBJ_STRING(x)->len,
+                  atom_name(y), atom_length(y));
   exit:
     return ok;
 }
@@ -613,15 +816,38 @@ int cons_push(Sxpr *list, Sxpr elt){
 void cons_free(Sxpr obj){
     Sxpr next;
     for(; CONSP(obj); obj = next){
-       next = CDR(obj);
-       objfree(CAR(obj));
-       hfree(obj);
+        next = CDR(obj);
+        objfree(CAR(obj));
+        hfree(obj);
     }
     if(!NULLP(obj)){
-       objfree(obj);
+        objfree(obj);
     }
 }
 
+/** Copy a cons. Recursively copies the car and cdr.
+ *
+ * @param obj to copy
+ */
+Sxpr cons_copy(Sxpr obj){
+    Sxpr v = ONULL;
+    Sxpr l = ONULL, x = ONONE;
+    for(l = obj; CONSP(l); l = CDR(l)){
+        x = objcopy(CAR(l));
+        if(NOMEMP(x)) goto exit;
+        x = cons_new(x, v);
+        if(NOMEMP(x)) goto exit;
+        v = x;
+    }
+    v = nrev(v);
+  exit:
+    if(NOMEMP(x)){
+        objfree(v);
+        v = ONOMEM;
+    }
+    return v;
+}
+
 /** Free a cons and its cdr cells, but not the car sxprs.
  * Does nothing if called on something that is not a cons.
  *
@@ -630,8 +856,8 @@ void cons_free(Sxpr obj){
 void cons_free_cells(Sxpr obj){
     Sxpr next;
     for(; CONSP(obj); obj = next){
-       next = CDR(obj);
-       hfree(obj);
+        next = CDR(obj);
+        hfree(obj);
     }
 }
 
@@ -698,26 +924,26 @@ int cons_length(Sxpr obj){
  */
 Sxpr nrev(Sxpr l){
     if(CONSP(l)){
-       // Iterate down the cells in the list making the cdr of
-       // each cell point to the previous cell. The last cell 
-       // is the head of the reversed list.
-       Sxpr prev = ONULL;
-       Sxpr cell = l;
-       Sxpr next;
-
-       while(1){
-           next = CDR(cell);
-           CDR(cell) = prev;
-           if(!CONSP(next)) break;
-           prev = cell;
-           cell = next;
-       }
-       l = cell;
+        // Iterate down the cells in the list making the cdr of
+        // each cell point to the previous cell. The last cell 
+        // is the head of the reversed list.
+        Sxpr prev = ONULL;
+        Sxpr cell = l;
+        Sxpr next;
+
+        while(1){
+            next = CDR(cell);
+            CDR(cell) = prev;
+            if(!CONSP(next)) break;
+            prev = cell;
+            cell = next;
+        }
+        l = cell;
     }
     return l;
 }
 
-/** Print the null sxpr.       
+/** Print the null sxpr.        
  *
  * @param io stream to print to
  * @param obj to print
@@ -761,6 +987,30 @@ static int bool_print(IOStream *io, Sxpr obj, unsigned flags){
     return IOStream_print(io, (OBJ_UINT(obj) ? k_true : k_false));
 }
 
+/** Print an error.
+ *
+ * @param io stream to print to
+ * @param obj to print
+ * @param flags print flags
+ * @return number of bytes written
+ */
+static int err_print(IOStream *io, Sxpr obj, unsigned flags){
+    int err = OBJ_INT(obj);
+    if(err < 0) err = -err;
+    return IOStream_print(io, "[error:%d:%s]", err, strerror(err));
+}
+
+/** Print the 'nomem' sxpr.
+ *
+ * @param io stream to print to
+ * @param obj to print
+ * @param flags print flags
+ * @return number of bytes written
+ */
+static int nomem_print(IOStream *io, Sxpr obj, unsigned flags){
+    return IOStream_print(io, "[ENOMEM]");
+}
+
 int sxprp(Sxpr obj, Sxpr name){
     return CONSP(obj) && objequal(CAR(obj), name);
 }
@@ -781,8 +1031,8 @@ Sxpr sxpr_name(Sxpr obj){
 }
 
 int sxpr_is(Sxpr obj, char *s){
-    if(ATOMP(obj)) return !strcmp(atom_name(obj), s);
-    if(STRINGP(obj)) return !strcmp(string_string(obj), s);
+    if(ATOMP(obj)) return string_eq(atom_name(obj), atom_length(obj), s, strlen(s));
+    if(STRINGP(obj)) return string_eq(string_string(obj), string_length(obj), s, strlen(s));
     return 0;
 }
 
@@ -915,11 +1165,11 @@ static int sym_equal_fn(void *x, void *y){
  */
 static void sym_free_fn(HashTable *table, HTEntry *entry){
     if(entry){
-       objfree(((ObjAtom*)entry->value)->name);
-       HTEntry_free(entry);
+        objfree(((ObjAtom*)entry->value)->name);
+        HTEntry_free(entry);
     }
 }
-       
+        
 /** Initialize the symbol table.
  *
  * @return 0 on sucess, error code otherwise
@@ -929,7 +1179,7 @@ static int init_symbols(void){
     if(symbols){
         symbols->key_hash_fn = sym_hash_fn;
         symbols->key_equal_fn = sym_equal_fn;
-       symbols->entry_free_fn = sym_free_fn;
+        symbols->entry_free_fn = sym_free_fn;
         return 0;
     }
     return -1;
@@ -950,8 +1200,8 @@ void cleanup_symbols(void){
 Sxpr get_symbol(char *sym){
     HTEntry *entry;
     if(!symbols){
-       if(init_symbols()) return ONOMEM;
-       return ONULL;
+        if(init_symbols()) return ONOMEM;
+        return ONULL;
     }
     entry = HashTable_get_entry(symbols, sym);
     if(entry){
@@ -969,10 +1219,10 @@ Sxpr get_symbol(char *sym){
 Sxpr intern(char *sym){
     Sxpr symbol = get_symbol(sym);
     if(NULLP(symbol)){
-       if(!symbols) return ONOMEM;
+        if(!symbols) return ONOMEM;
         symbol = atom_new(sym);
         if(!NOMEMP(symbol)){
-           OBJ_ATOM(symbol)->interned = TRUE;
+            OBJ_ATOM(symbol)->interned = TRUE;
             HashTable_add(symbols, atom_name(symbol), get_ptr(symbol));
         }
     }
index 761b8b2da711dcda07acc5a53b4a9fd1afe1d100..c9acd7b25f301aaa599ebc00b52508477e4bc4aa 100644 (file)
@@ -52,15 +52,80 @@ typedef struct Sxpr {
     /** Sxpr type. */
     TypeCode type;
     union {
-       /** Sxpr value. */
+        /** Sxpr value. */
         unsigned long ul;
-       /** Pointer. */
+        /** Pointer. */
         void *ptr;
     } v;
 } Sxpr;
 
-/** Sxpr type to indicate out of memory. */
-#define T_NOMEM      ((TypeCode)-1)
+/** Get the integer value from an sxpr.
+ *
+ * @param obj sxpr
+ * @return value
+ */
+static inline unsigned long get_ul(Sxpr obj){
+    return obj.v.ul;
+}
+
+/** Get the pointer value from an sxpr.
+ *
+ * @param obj sxpr
+ * @return value
+ */
+static inline void * get_ptr(Sxpr obj){
+    return obj.v.ptr;
+}
+
+/** Create an sxpr containing a pointer.
+ *
+ * @param ty typecode
+ * @param val pointer
+ * @return sxpr
+ */
+static inline Sxpr obj_ptr(TypeCode ty, void *val){
+    return (Sxpr){ .type= ty, .v= { .ptr= val } };
+}
+
+/** Create an sxpr containing an integer.
+ *
+ * @param ty typecode
+ * @param val integer
+ * @return sxpr
+ */
+static inline Sxpr obj_ul(TypeCode ty, unsigned long val){
+    return (Sxpr){ .type= ty, .v= { .ul= val } };
+}
+
+/** Get the type of an sxpr.
+ *
+ * @param obj sxpr
+ * @return type
+ */
+static inline TypeCode get_type(Sxpr obj){
+    return obj.type;
+}
+
+/** Check the type of an sxpr.
+ *
+ * @param obj sxpr
+ * @param type to check
+ * @return 1 if has the type, 0 otherwise
+ */
+static inline int has_type(Sxpr obj, TypeCode type){
+    return get_type(obj) == type;
+}
+
+/** Compare sxprs for literal equality of type and value.
+ *
+ * @param x sxpr to compare
+ * @param y sxpr to compare
+ * @return 1 if equal, 0 otherwise
+ */
+static inline int eq(Sxpr x, Sxpr y){
+    return ((get_type(x) == get_type(y)) && (get_ul(x) == get_ul(y)));
+}
+
 /** The 'unspecified' sxpr. */
 #define T_NONE       ((TypeCode)0)
 /** The empty list. */
@@ -79,6 +144,13 @@ typedef struct Sxpr {
 
 /** An error. */
 #define T_ERR        ((TypeCode)40)
+/** Sxpr type to indicate out of memory. */
+#define T_NOMEM      ((TypeCode)41)
+
+typedef struct ObjString {
+    int len;
+    char data[];
+} ObjString;
 
 /** An atom. */
 typedef struct ObjAtom {
@@ -93,41 +165,27 @@ typedef struct ObjCons {
     Sxpr cdr;
 } ObjCons;
 
-/** A vector. */
-typedef struct ObjVector {
-    int n;
-    Sxpr data[0];
-} ObjVector;
-
 /** Flags for sxpr printing. */
 enum PrintFlags {
     PRINT_RAW           = 0x001,
     PRINT_TYPE          = 0x002,
     PRINT_PRETTY        = 0x004,
-    PRINT_NUM           = 0x008,
+    PRINT_COUNTED       = 0x008,
+    PRINT_ADDR          = 0x010,
 };
 
+extern int _string_print(IOStream *io, char *str, int n, unsigned flags);
+extern int _string_print_raw(IOStream *io, char *str, int n);
+extern int _string_print_counted(IOStream *io, char *str, int n);
+extern int _string_print_quoted(IOStream *io, char *str, int n);
+extern int _string_print_string(IOStream *io, char *str, int n);
+
 /** An integer sxpr.
  *
  * @param ty type
  * @param val integer value
  */
-#define OBJI(ty, val) (Sxpr){ type: (ty), v: { ul: (val) }}
-
-/** A pointer sxpr.
- * If the pointer is non-null, returns an sxpr containing it.
- * If the pointer is null, returns ONOMEM.
- *
- * @param ty type
- * @param val pointer
- */
-#define OBJP(ty, val) ((val) ? (Sxpr){ type: (ty), v: { ptr: (val) }} : ONOMEM)
-
-/** Make an integer sxpr containing a pointer.
- *
- * @param val pointer
- */
-#define PTR(val) OBJP(T_UINT, (void*)(val))
+#define OBJI(ty, val) obj_ul(ty, val)
 
 /** Make an integer sxpr.
  * @param x value
@@ -155,6 +213,40 @@ enum PrintFlags {
 /** True constant. */
 #define OTRUE         OBJI(T_BOOL,  1)
 
+/** A pointer sxpr.
+ * If the pointer is non-null, returns an sxpr containing it.
+ * If the pointer is null, returns ONOMEM.
+ *
+ * @param ty type
+ * @param val pointer
+ */
+static inline Sxpr OBJP(int ty, void *val){
+    return (val ? obj_ptr(ty, val) : ONOMEM);
+}
+
+/** Make an integer sxpr containing a pointer.
+ *
+ * @param val pointer
+ */
+#define PTR(val) OBJP(T_UINT, (void*)(val))
+
+/** Allocate some memory and return an sxpr containing it.
+ * Returns ONOMEM if allocation failed.
+ *
+ * @param n number of bytes to allocate
+ * @param ty typecode
+ * @return sxpr
+ */
+#define halloc(_n, _ty) OBJP(_ty, allocate(_n))
+
+/** Allocate an sxpr containing a pointer to the given type.
+ *
+ * @param _ctype type (uses sizeof to determine how many bytes to allocate)
+ * @param _tycode typecode
+ * @return sxpr, ONOMEM if allocation failed
+ */
+#define HALLOC(_ctype, _tycode) halloc(sizeof(_ctype), _tycode)
+
 /* Recognizers for the various sxpr types.  */
 #define ATOMP(obj)        has_type(obj, T_ATOM)
 #define BOOLP(obj)        has_type(obj, T_BOOL)
@@ -176,7 +268,7 @@ enum PrintFlags {
 /* Conversions of sxprs to their values.
  * No checking is done.
  */
-#define OBJ_STRING(x)  ((char*)get_ptr(x))
+#define OBJ_STRING(x)  ((ObjString*)get_ptr(x))
 #define OBJ_CONS(x)    ((ObjCons*)get_ptr(x))
 #define OBJ_ATOM(x)    ((ObjAtom*)get_ptr(x))
 #define OBJ_SET(x)     ((ObjSet*)get_ptr(x))
@@ -188,73 +280,6 @@ enum PrintFlags {
 #define CDAR(x)        (CDR(CAR(x)))
 #define CDDR(x)        (CDR(CDR(x)))
 
-/** Get the integer value from an sxpr.
- *
- * @param obj sxpr
- * @return value
- */
-static inline unsigned long get_ul(Sxpr obj){
-    return obj.v.ul;
-}
-
-/** Get the pointer value from an sxpr.
- *
- * @param obj sxpr
- * @return value
- */
-static inline void * get_ptr(Sxpr obj){
-    return obj.v.ptr;
-}
-
-/** Create an sxpr containing a pointer.
- *
- * @param type typecode
- * @param val pointer
- * @return sxpr
- */
-static inline Sxpr obj_ptr(TypeCode type, void *val){
-    return (Sxpr){ type: type, v: { ptr: val } };
-}
-
-/** Create an sxpr containing an integer.
- *
- * @param type typecode
- * @param val integer
- * @return sxpr
- */
-static inline Sxpr obj_ul(TypeCode type, unsigned long val){
-    return (Sxpr){ type: type, v: { ul: val } };
-}
-
-/** Get the type of an sxpr.
- *
- * @param obj sxpr
- * @return type
- */
-static inline TypeCode get_type(Sxpr obj){
-    return obj.type;
-}
-
-/** Check the type of an sxpr.
- *
- * @param obj sxpr
- * @param type to check
- * @return 1 if has the type, 0 otherwise
- */
-static inline int has_type(Sxpr obj, TypeCode type){
-    return get_type(obj) == type;
-}
-
-/** Compare sxprs for literal equality of type and value.
- *
- * @param x sxpr to compare
- * @param y sxpr to compare
- * @return 1 if equal, 0 otherwise
- */
-static inline int eq(Sxpr x, Sxpr y){
-    return ((get_type(x) == get_type(y)) && (get_ul(x) == get_ul(y)));
-}
-
 /** Checked version of CAR
  *
  * @param x sxpr
@@ -273,28 +298,10 @@ static inline Sxpr cdr(Sxpr x){
     return (CONSP(x) ? CDR(x) : ONULL);
 }
 
-/** Allocate some memory and return an sxpr containing it.
- * Returns ONOMEM if allocation failed.
- *
- * @param n number of bytes to allocate
- * @param ty typecode
- * @return sxpr
- */
-static inline Sxpr halloc(size_t n,  TypeCode ty){
-    return OBJP(ty, allocate(n));
-}
-
-/** Allocate an sxpr containing a pointer to the given type.
- *
- * @param ty type (uses sizeof to determine how many bytes to allocate)
- * @param code typecode
- * @return sxpr, ONOMEM if allocation failed
- */
-#define HALLOC(ty, code) halloc(sizeof(ty), code)
-
 typedef int ObjPrintFn(IOStream *io, Sxpr obj, unsigned flags);
 typedef int ObjEqualFn(Sxpr obj, Sxpr other);
 typedef void ObjFreeFn(Sxpr obj);
+typedef Sxpr ObjCopyFn(Sxpr obj);
 
 /** An sxpr type definition. */
 typedef struct SxprType {
@@ -304,6 +311,7 @@ typedef struct SxprType {
     ObjPrintFn *print;
     ObjEqualFn *equal;
     ObjFreeFn *free;
+    ObjCopyFn *copy;
 } SxprType;
 
 
@@ -321,6 +329,7 @@ static inline void hfree(Sxpr x){
 extern int objprint(IOStream *io, Sxpr x, unsigned flags);
 extern int objequal(Sxpr x, Sxpr y);
 extern void objfree(Sxpr x);
+extern Sxpr objcopy(Sxpr x);
 
 extern void cons_free_cells(Sxpr obj);
 extern Sxpr intern(char *s);
@@ -341,8 +350,10 @@ extern Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v);
 
 extern Sxpr atom_new(char *name);
 extern char * atom_name(Sxpr obj);
+extern int atom_length(Sxpr obj);
 
 extern Sxpr string_new(char *s);
+extern Sxpr string_new_n(char *s, int n);
 extern char * string_string(Sxpr obj);
 extern int string_length(Sxpr obj);
 
@@ -405,15 +416,20 @@ static inline Sxpr mkbool(int b){
 #define k_true         "true"
 #define k_false        "false"
 
-#define c_var          '$'
 #define c_escape       '\\'
 #define c_single_quote '\''
 #define c_double_quote '"'
 #define c_string_open  c_double_quote
 #define c_string_close c_double_quote
-#define c_data_open    '['
-#define c_data_close   ']'
-#define c_binary       '*'
+
+#define c_data_open    '<'
+#define c_data_quote   '<'
+#define c_data_count   '*'
+//#define c_data_open    '['
+//#define c_data_close   ']'
+//#define c_binary       '*'
+
+#define c_var          '$'
 #define c_eval         '!'
 #define c_concat_open  '{'
 #define c_concat_close '}'
index d32ef959b3c2b04e3a83cf8c6552f0db0225087f..870f68f1a1e9db88b15fa23609e766b452320d4d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
+ * Copyright (C) 2001 - 2005 Mike Wray <mike.wray@hp.com>
  *
  * This library is free software; you can redistribute it and/or modify
  * it under the terms of the GNU Lesser General Public License as
@@ -26,6 +26,8 @@
 #  include <errno.h>
 #endif
 
+#include "sys_net.h"
+
 #include "iostream.h"
 #include "lexis.h"
 #include "sxpr_parser.h"
  * @author Mike Wray <mike.wray@hpl.hp.com>
  */
 
+#ifdef DEBUG
 #define dprintf(fmt, args...) IOStream_print(iostdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args)
+#else
+#define dprintf(fmt, args...) do{ }while(0)
+#endif
+
 #undef printf
 #define printf(fmt, args...)   IOStream_print(iostdout, fmt, ##args)
 
-static void reset(Parser *z);
-static int inputchar(Parser *p, char c);
-static int savechar(Parser *p, char c);
-extern void parse_error(Parser *in);
-extern void parse_error_id(Parser *in, ParseErrorId id);
-
-static int begin_start(Parser *p, char c);
 static int state_start(Parser *p, char c);
-static int end_start(Parser *p);
-
-static int begin_comment(Parser *p, char c);
-static int state_comment(Parser *p, char c);
-static int end_comment(Parser *p);
-
-static int begin_string(Parser *p, char c);
-static int state_string(Parser *p, char c);
-static int end_string(Parser *p);
-static int state_escape(Parser *p, char c);
-static int state_octal(Parser *p, char c);
-static int state_hex(Parser *p, char c);
-
-static int begin_atom(Parser *p, char c);
-static int state_atom(Parser *p, char c);
-static int end_atom(Parser *p);
-
-static int state_list(Parser *p, char c);
-static int begin_list(Parser *p, char c);
-static int end_list(Parser *p);
+static int begin_start(Parser *p, char c);
 
 /** Print a parse error.
  *
  * @param in parser
  * @param msg format followed by printf arguments
  */
-void eprintf(Parser *in, char *msg, ...){
+static void eprintf(Parser *in, char *msg, ...){
     va_list args;
     if(in->error_out){
         va_start(args, msg);
@@ -94,7 +75,7 @@ void eprintf(Parser *in, char *msg, ...){
  * @param in parser
  * @param msg format followed by printf arguments
  */
-void wprintf(Parser *in, char *msg, ...){
+static void wprintf(Parser *in, char *msg, ...){
     va_list args;
     if(in->error_out){
         va_start(args, msg);
@@ -107,8 +88,8 @@ void wprintf(Parser *in, char *msg, ...){
 
 /** Record defining the message for a parse error. */
 typedef struct {
-  ParseErrorId id;
-  char *message;
+    ParseErrorId id;
+    char *message;
 } ParseError;
 
 /** Format for printing parse error messages. */
@@ -116,156 +97,243 @@ typedef struct {
 
 /** Message catalog for the parse error codes. */
 static ParseError catalog[] = {
-  { PARSE_ERR_UNSPECIFIED,            "unspecified error" },
-  { PARSE_ERR_NOMEM,                  "out of memory" },
-  { PARSE_ERR_UNEXPECTED_EOF,         "unexpected end of input" },
-  { PARSE_ERR_TOKEN_TOO_LONG,         "token too long" },
-  { PARSE_ERR_INVALID_SYNTAX,         "syntax error" },
-  { PARSE_ERR_INVALID_ESCAPE,         "invalid escape" },
-  { 0, NULL }
+    { PARSE_ERR_UNSPECIFIED,            "unspecified error" },
+    { PARSE_ERR_NOMEM,                  "out of memory" },
+    { PARSE_ERR_UNEXPECTED_EOF,         "unexpected end of input" },
+    { PARSE_ERR_TOKEN_TOO_LONG,         "token too long" },
+    { PARSE_ERR_INVALID_SYNTAX,         "syntax error" },
+    { PARSE_ERR_INVALID_ESCAPE,         "invalid escape" },
+    { 0, NULL }
 };
 
 /** Number of entries in the message catalog. */
 const static int catalog_n = sizeof(catalog)/sizeof(ParseError);
 
-void ParserState_free(ParserState *z){
-    if(!z) return;
-    objfree(z->val);
-    deallocate(z);
+/** Set the parser error stream.
+ * Parse errors are reported on the the error stream if it is non-null.
+ * 
+ * @param z parser
+ * @param error_out error stream
+ */
+void Parser_set_error_stream(Parser *z, IOStream *error_out){
+    z->error_out = error_out;
 }
 
-int ParserState_new(ParserStateFn *fn, char *name,
-                    ParserState *parent, ParserState **val){
-    int err = 0;
-    ParserState *z;
-    z = ALLOCATE(ParserState);
-    if(z){
-        z->name = name;
-        z->fn = fn;
-        z->parent = parent;
-        z->val = ONULL;
-    } else {
-        err = -ENOMEM;
+/** Get the parser error message for an error code.
+ *
+ * @param id error code
+ * @return error message (empty string if the code is unknown)
+ */
+static char *get_message(ParseErrorId id){
+    int i;
+    for(i = 0; i < catalog_n; i++){
+        if(id == catalog[i].id){
+            return catalog[i].message;
+        }
     }
-    if(!err) *val = z;
-    return err;
+    return "";
 }
 
-/** Free a parser.
- * No-op if the parser is null.
+/** Get the line number.
  *
- * @param z parser 
+ * @param in parser
  */
-void Parser_free(Parser *z){
-    if(!z) return;
-    objfree(z->val);
-    z->val = ONONE;
-    deallocate(z);
+static int get_line(Parser *in){
+    return in->line_no;
 }
 
-/** Create a new parser. The error stream defaults to null.
+/** Get the column number.
+ *
+ * @param in parser
  */
-Parser * Parser_new(void){
-    Parser *z = ALLOCATE(Parser);
-    int err = -ENOMEM;
-  
-    if(!z) goto exit;
-    err = 0;
-    reset(z);
-  exit:
-    if(err){
-        Parser_free(z);
-        z = NULL;
-    }
-    return z;
+static int get_column(Parser *in){
+    return in->char_no;
 }
 
-/** Get the next character.
- * Records the character read in the parser,
- * and sets the line and character counts.
+/** Get the line number the current token started on.
+ *
+ * @param in parser
+ */
+static int get_tok_line(Parser *in){
+    return in->tok_begin_line;
+}
+
+/** Get the column number the current token started on.
+ *
+ * @param in parser
+ */
+static int get_tok_column(Parser *in){
+    return in->tok_begin_char;
+}
+
+/** Return the current token.
+ * The return value points at the internal buffer, so
+ * it must not be modified (or freed). Use copy_token() if you need a copy.
  *
  * @param p parser
- * @return error flag: 0 on success, non-zero on error
+ * @return token
  */
-static int inputchar(Parser *p, char c){
-    int err = 0;
-    if(c=='\n'){
-        p->line_no++;
-        p->char_no = 0;
-    } else {
-        p->char_no++;
+char *peek_token(Parser *p){
+    return p->tok;
+}
+
+int token_len(Parser *p){
+    return p->tok_end - p->tok;
+}
+
+/** Return a copy of the current token.
+ * The returned value should be freed when finished with.
+ *
+ * @param p parser
+ * @return copy of token
+ */
+char *copy_token(Parser *p){
+    int n = token_len(p);
+    char *buf = allocate(n + 1);
+    if(buf){
+        memcpy(buf, peek_token(p), n);
+        buf[n] = '\0';
     }
-    return err;
+    return buf;
 }
 
-static int savechar(Parser *p, char c){
-    int err = 0;
-    if(p->buf_i >= p->buf_n){
-        err = -ENOMEM;
-        goto exit;
+void new_token(Parser *p){
+    memset(p->buf, 0, p->buf_end - p->buf);
+    p->tok = p->buf;
+    p->tok_end = p->tok;
+    p->tok_begin_line = p->line_no;
+    p->tok_begin_char = p->char_no;
+}
+
+/** Report a parse error.
+ * Does nothing if the error stream is null or there is no error.
+ *
+ * @param in parser
+ */
+static void report_error(Parser *in){
+    if(in->error_out && in->err){
+        char *msg = get_message(in->err);
+        char *tok = peek_token(in);
+        IOStream_print(in->error_out, PARSE_ERR_FMT,
+                       get_tok_line(in), get_tok_column(in), msg);
+        if(tok && tok[0]){
+            IOStream_print(in->error_out, " '%s'", tok);
+        }
+        IOStream_print(in->error_out, "\n");
     }
-    p->buf[p->buf_i] = c;
-    p->buf_i++;
-  exit:
-    return err;
 }
 
-int Parser_input_char(Parser *p, char c){
-    int err = 0;
-    if(at_eof(p)){
-        //skip;
-    } else {
-        inputchar(p, c);
+/** Get the error message for the current parse error code.
+ * Does nothing if there is no error.
+ *
+ * @param in parser
+ * @param buf where to place the message
+ * @param n maximum number of characters to place in buf
+ * @return current error code (zero for no error)
+ */
+int Parser_error_message(Parser *in, char *buf, int n){
+    if(in->err){
+        char *msg = get_message(in->err);
+        snprintf(buf, n, PARSE_ERR_FMT, get_tok_line(in),
+                 get_tok_column(in), msg);
     }
-    if(!p->state){
-        err = begin_start(p, c);
-        if(err) goto exit;
+    return in->err;
+}
+
+/** Flag a parse error. All subsequent reads will fail.
+ * Does not change the parser error code if it is already set.
+ *
+ * @param in parser
+ * @param id error code
+ */
+int Parser_error_id(Parser *in, ParseErrorId id){
+    if(!in->err){
+        in->err = id;
+        report_error(in);
     }
-    err = p->state->fn(p, c);
-  exit:
-    return err;
+    return -EINVAL;
 }
 
-int Parser_input_eof(Parser *p){
-    int err = 0;
-    p->eof = 1;
-    err = Parser_input_char(p, IOSTREAM_EOF);
-    return err;
+/** Flag an unspecified parse error.
+ *
+ * @param in parser
+ */
+int Parser_error(Parser *in){
+    return Parser_error_id(in, PARSE_ERR_INVALID_SYNTAX);
 }
 
-int Parser_input(Parser *p, char *buf, int buf_n){
-    int err = 0;
-    int i = 0;
-    if(buf_n <= 0){
-        err = Parser_input_eof(p);
-        goto exit;
-    }
-    for(i = 0; i<buf_n; i++){
-        err = Parser_input_char(p, buf[i]);
-        if(err) goto exit;
-    }
-  exit:
-    err = (err < 0 ? err : buf_n);
-    return err;
+/** Test if the parser's error flag is set.
+ *
+ * @param in parser
+ * @return 1 if set, 0 otherwise
+ */
+int Parser_has_error(Parser *in){
+    return (in->err > 0);
 }
 
-int Parser_push(Parser *p, ParserStateFn *fn, char *name){
-    int err = 0;
-    err = ParserState_new(fn, name, p->state, &p->state);
+/** Test if the parser is at end of input.
+ *
+ * @param in parser
+ * @return 1 if at EOF, 0 otherwise
+ */
+int Parser_at_eof(Parser *p){
+    return p->eof;
+}
+
+void ParserState_free(ParserState *z){
+    if(!z) return;
+    objfree(z->val);
+    deallocate(z);
+}
+
+int ParserState_new(ParserStateFn *fn, char *name,
+                    ParserState *parent, ParserState **val){
+    int err = -ENOMEM;
+    ParserState *z;
+    z = ALLOCATE(ParserState);
+    if(!z) goto exit;
+    z->name = name;
+    z->fn = fn;
+    z->parent = parent;
+    z->val = ONULL;
+    err = 0;
+  exit:
+    *val = (err ? NULL : z);
     return err;
 }
-        
-int Parser_pop(Parser *p){
-    int err = 0;
+
+void Parser_pop(Parser *p){
     ParserState *s = p->state;
+    if(!s) return;
     p->state = s->parent;
     if (p->start_state == s) {
         p->start_state = NULL;
     }
     ParserState_free(s);
-    return err;
 }
 
+/** Free a parser.
+ * No-op if the parser is null.
+ *
+ * @param z parser 
+ */
+void Parser_free(Parser *z){
+    if(!z) return;
+    // Hmmm. Need to free states, but careful about double free of values.
+    while(z->state){
+        objfree(z->state->val);
+        Parser_pop(z);
+    }
+    if(z->buf) deallocate(z->buf);
+    objfree(z->val);
+    z->val = ONONE;
+    deallocate(z);
+}
+
+int Parser_push(Parser *p, ParserStateFn *fn, char *name){
+    return ParserState_new(fn, name, p->state, &p->state);
+}
+        
 int Parser_return(Parser *p){
     int err = 0;
     Sxpr val = ONONE;
@@ -275,8 +343,7 @@ int Parser_return(Parser *p){
     }
     val = p->state->val;
     p->state->val = ONONE;
-    err = Parser_pop(p);
-    if(err) goto exit;
+    Parser_pop(p);
     if(p->state){
         err = cons_push(&p->state->val, val);
     } else {
@@ -290,52 +357,102 @@ int Parser_return(Parser *p){
     return err;
 }
 
-/** Determine if a character is a separator.
+/** Reset the fields of a parser to initial values.
  *
- * @param p parser
- * @param c character to test
- * @return 1 if a separator, 0 otherwise
+ * @param z parser
  */
-static int is_separator(Parser *p, char c){
-    return in_sep_class(c);
+static void reset(Parser *z){
+    // leave flags
+    // leave error_out
+    while(z->state){
+        Parser_pop(z);
+    }
+    z->val = ONONE;
+    z->eof = 0;
+    z->err = 0;
+    z->line_no = 1;
+    z->char_no = 0;
+    memset(z->buf, 0, z->buf_end - z->buf);
+    z->tok = z->buf;
+    z->tok_end = z->tok;
+    z->tok_begin_line = 0;
+    z->tok_begin_char = 0;
+    z->start_state = NULL;
 }
 
-/** Return the current token.
- * The return value points at the internal buffer, so
- * it must not be modified (or freed). Use copy_token() if you need a copy.
- *
- * @param p parser
- * @return token
+/** Create a new parser. The error stream defaults to null.
  */
-char *peek_token(Parser *p){
-    return p->buf;
+Parser * Parser_new(void){
+    Parser *z = ALLOCATE(Parser);
+    int n = PARSER_BUF_SIZE;
+    int err = -ENOMEM;
+  
+    if(!z) goto exit;
+    z->buf = allocate(n);
+    if(!z->buf) goto exit;
+    err = 0;
+    z->buf_end = z->buf + n;
+    z->begin = begin_start;
+    reset(z);
+  exit:
+    if(err){
+        Parser_free(z);
+        z = NULL;
+    }
+    return z;
 }
 
-/** Return a copy of the current token.
- * The returned value should be freed when finished with.
+/** Get the next character.
+ * Records the character read in the parser,
+ * and sets the line and character counts.
  *
  * @param p parser
- * @return copy of token
+ * @return error flag: 0 on success, non-zero on error
  */
-char *copy_token(Parser *p){
-    return strdup(peek_token(p));
-}
-
-static int do_intern(Parser *p){
+static int input_char(Parser *p, char c){
     int err = 0;
-    Sxpr obj = intern(peek_token(p));
-    if(NOMEMP(obj)){
-        err = -ENOMEM;
+    if(c=='\n'){
+        p->line_no++;
+        p->char_no = 0;
     } else {
-        p->state->val = obj;
+        p->char_no++;
     }
     return err;
 }
 
-static int do_string(Parser *p){
+int save_char(Parser *p, char c){
+    int err = 0;
+    if(p->tok_end >= p->buf_end){
+        int buf_n = (p->buf_end - p->buf) + PARSER_BUF_INCREMENT;
+        char *buf = allocate(buf_n);
+        if(!buf){
+            err = -ENOMEM;
+            goto exit;
+        }
+        memcpy(buf, p->buf, p->tok_end - p->buf);
+        p->buf_end = buf + buf_n;
+        p->tok     = buf + (p->tok     - p->buf);
+        p->tok_end = buf + (p->tok_end - p->buf);
+        deallocate(p->buf);
+        p->buf = buf;
+    }
+    *p->tok_end++ = c;
+  exit:
+    return err;
+}
+
+/** Determine if a character is a separator.
+ *
+ * @param p parser
+ * @param c character to test
+ * @return 1 if a separator, 0 otherwise
+ */
+static int is_separator(Parser *p, char c){
+    return in_sep_class(c);
+}
+
+int Parser_set_value(Parser *p, Sxpr obj){
     int err = 0;
-    Sxpr obj;
-    obj = string_new(peek_token(p));
     if(NOMEMP(obj)){
         err = -ENOMEM;
     } else {
@@ -343,15 +460,33 @@ static int do_string(Parser *p){
     }
     return err;
 }
+    
+int Parser_intern(Parser *p){
+    Sxpr obj = intern(peek_token(p));
+    return Parser_set_value(p, obj);
+}
 
-void newtoken(Parser *p){
-    memset(p->buf, 0, p->buf_n);
-    p->buf_i = 0;
-    p->tok_begin_line = p->line_no;
-    p->tok_begin_char = p->char_no;
+int Parser_atom(Parser *p){
+    Sxpr obj = atom_new(peek_token(p));
+    return Parser_set_value(p, obj);
+}
+
+int Parser_string(Parser *p){
+    Sxpr obj = string_new_n(peek_token(p), token_len(p));
+    return Parser_set_value(p, obj);
+}
+
+int Parser_data(Parser *p){
+    Sxpr obj = string_new_n(peek_token(p), token_len(p));
+    return Parser_set_value(p, obj);
+}
+
+int Parser_uint(Parser *p){
+    unsigned int x = htonl(*(unsigned int *)peek_token(p));
+    return Parser_set_value(p, OINT(x));
 }
 
-int get_escape(char c, char *d){
+static int get_escape(char c, char *d){
     int err = 0;
     switch(c){
     case 'a':            *d = '\a'; break;
@@ -377,15 +512,18 @@ int Parser_ready(Parser *p){
 Sxpr Parser_get_val(Parser *p){
     Sxpr v = ONONE;
     if(CONSP(p->val)){
-        v = CAR(p->val);
-        p->val = CDR(p->val);
-    } else if (CONSP(p->start_state->val)){
+    } else if (p->start_state && CONSP(p->start_state->val)){
         p->val = p->start_state->val;
         p->val = nrev(p->val);
         p->start_state->val = ONULL;
-        v = CAR(p->val);
-        p->val = CDR(p->val);
-    }        
+    }  else {
+        goto exit;
+    }
+    Sxpr w = p->val;
+    v = CAR(w);
+    p->val = CDR(w);
+    hfree(w);
+  exit:
     return v;
 }
 
@@ -401,151 +539,51 @@ Sxpr Parser_get_all(Parser *p){
     }
     return v;
 }
-    
-int begin_start(Parser *p, char c){
-    int err = 0;
-    err = Parser_push(p, state_start, "start");
-    if(err) goto exit;
-    p->start_state = p->state;
-  exit:
-    return err;
-}
 
-int state_start(Parser *p, char c){
+static int state_comment(Parser *p, char c){
     int err = 0;
-    if(at_eof(p)){
-        err = end_start(p);
-    } else if(in_space_class(c)){
-        //skip
-    } else if(in_comment_class(c)){
-        begin_comment(p, c);
-    } else if(c == c_list_open){
-        begin_list(p, c);
-    } else if(c == c_list_close){
-        parse_error(p);
-        err = -EINVAL;
-    } else if(in_string_quote_class(c)){
-        begin_string(p, c);
-    } else if(in_printable_class(c)){
-        begin_atom(p, c);
-    } else if(c == 0x04){
-        //ctrl-D, EOT: end-of-text.
-        Parser_input_eof(p);
+    if(c == '\n' || Parser_at_eof(p)){
+        Parser_pop(p);
     } else {
-        parse_error(p);
-        err = -EINVAL;
+        err = input_char(p, c);
     }
     return err;
 }
 
-int end_start(Parser *p){
-    int err = 0;
-    err = Parser_return(p);
-    return err;
-}
-
-int begin_comment(Parser *p, char c){
+static int begin_comment(Parser *p, char c){
     int err = 0;
     err = Parser_push(p, state_comment, "comment");
     if(err) goto exit;
-    err = inputchar(p, c);
-  exit:
-    return err;
-}
-
-int state_comment(Parser *p, char c){
-    int err = 0;
-    if(c == '\n' || at_eof(p)){
-        err = end_comment(p);
-    } else {
-        err = inputchar(p, c);
-    }
-    return err;
-}
-
-int end_comment(Parser *p){
-    return Parser_pop(p);
-}
-
-int begin_string(Parser *p, char c){
-    int err = 0;
-    err = Parser_push(p, state_string, "string");
-    if(err) goto exit;
-    newtoken(p);
-    p->state->delim = c;
-  exit:
-    return err;
-}
-
-int state_string(Parser *p, char c){
-    int err = 0;
-    if(at_eof(p)){
-        parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
-        err = -EINVAL;
-    } else if(c == p->state->delim){
-        err = end_string(p);
-    } else if(c == '\\'){
-        err = Parser_push(p, state_escape, "escape");
-    } else {
-        err = savechar(p, c);
-    }
-    return err;
-}
-
-int end_string(Parser *p){
-    int err = 0;
-    err = do_string(p);
-    if(err) goto exit;
-    err = Parser_return(p);
+    err = input_char(p, c);
   exit:
     return err;
 }
 
-int state_escape(Parser *p, char c){
+static int end_string(Parser *p){
     int err = 0;
-    char d;
-    if(at_eof(p)){
-        parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
-        err = -EINVAL;
-        goto exit;
-    }
-    if(get_escape(c, &d) == 0){
-        err = savechar(p, d);
-        if(err) goto exit;
-        err = Parser_pop(p);
-    } else if(c == 'x'){
-        p->state->fn = state_hex;
-        p->state->ival = 0;
-        p->state->count = 0;
-    } else {
-        p->state->fn = state_octal;
-        p->state->ival = 0;
-        p->state->count = 0;
-        err = Parser_input_char(p, c);
-    }
+    err = Parser_string(p);
+    if(err) goto exit;
+    err = Parser_return(p);
   exit:
     return err;
 }
 
-int octaldone(Parser *p){
+static int octaldone(Parser *p){
     int err = 0;
     char d = (char)(p->state->ival & 0xff);
-    err = Parser_pop(p);
-    if(err) goto exit;
+    Parser_pop(p);
     err = Parser_input_char(p, d);
-  exit:
     return err;
 }
 
-int octaldigit(Parser *p, char c){
+static int octaldigit(Parser *p, int d){
     int err = 0;
     p->state->ival *= 8;
-    p->state->ival += c - '0'
+    p->state->ival += d
     p->state->count++;
     if(err) goto exit;
     if(p->state->ival < 0 || p->state->ival > 0xff){
-        parse_error(p);
-        err = -EINVAL;
+        err = Parser_error(p);
         goto exit;
     }
     if(p->state->count == 3){
@@ -555,14 +593,13 @@ int octaldigit(Parser *p, char c){
     return err;
 }
 
-int state_octal(Parser *p, char c){
+static int state_octal(Parser *p, char c){
     int err = 0;
-    if(at_eof(p)){
-        parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
-        err = -EINVAL;
+    if(Parser_at_eof(p)){
+        err = Parser_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
         goto exit;
     } else if('0' <= c && c <= '7'){
-        err = octaldigit(p, c);
+        err = octaldigit(p, c - '0');
     } else {
         err = octaldone(p);
         if(err) goto exit;
@@ -572,25 +609,22 @@ int state_octal(Parser *p, char c){
     return err;
 }
 
-int hexdone(Parser *p){
+static int hexdone(Parser *p){
     int err = 0;
     char d = (char)(p->state->ival & 0xff);
-    err = Parser_pop(p);
-    if(err) goto exit;
+    Parser_pop(p);
     err = Parser_input_char(p, d);
-  exit:
     return err;
 }
     
-int hexdigit(Parser *p, char c, char d){
+static int hexdigit(Parser *p, int d){
     int err = 0;
     p->state->ival *= 16;
-    p->state->ival += c - d; 
+    p->state->ival += d; 
     p->state->count++;
     if(err) goto exit;
     if(p->state->ival < 0 || p->state->ival > 0xff){
-        parse_error(p);
-        err = -EINVAL;
+        err = Parser_error(p);
         goto exit;
     }
     if(p->state->count == 2){
@@ -600,20 +634,19 @@ int hexdigit(Parser *p, char c, char d){
     return err;
 }
     
-int state_hex(Parser *p, char c){
+static int state_hex(Parser *p, char c){
     int err = 0;
-    if(at_eof(p)){
-        parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
-        err = -EINVAL;
+    if(Parser_at_eof(p)){
+        err = Parser_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
         goto exit;
     } else if('0' <= c && c <= '9'){
-        err = hexdigit(p, c, '0');
+        err = hexdigit(p, c - '0');
     } else if('A' <= c && c <= 'F'){
-        err = hexdigit(p, c, 'A');
+        err = hexdigit(p, c - 'A' + 10);
     } else if('a' <= c && c <= 'f'){
-        err = hexdigit(p, c, 'a');
+        err = hexdigit(p, c - 'a' + 10);
     } else if(p->state->count){
-        err =hexdone(p);
+        err = hexdone(p);
         if(err) goto exit;
         Parser_input_char(p, c);
     }
@@ -621,19 +654,67 @@ int state_hex(Parser *p, char c){
     return err;
 }
 
-int begin_atom(Parser *p, char c){
+static int state_escape(Parser *p, char c){
     int err = 0;
-    err = Parser_push(p, state_atom, "atom");
+    char d;
+    if(Parser_at_eof(p)){
+        err = Parser_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
+        goto exit;
+    }
+    if(get_escape(c, &d) == 0){
+        err = save_char(p, d);
+        if(err) goto exit;
+        Parser_pop(p);
+    } else if(c == 'x'){
+        p->state->fn = state_hex;
+        p->state->ival = 0;
+        p->state->count = 0;
+    } else {
+        p->state->fn = state_octal;
+        p->state->ival = 0;
+        p->state->count = 0;
+        err = Parser_input_char(p, c);
+    }
+  exit:
+    return err;
+}
+
+static int state_string(Parser *p, char c){
+    int err = 0;
+    if(Parser_at_eof(p)){
+        err = Parser_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
+    } else if(c == p->state->delim){
+        err = end_string(p);
+    } else if(c == '\\'){
+        err = Parser_push(p, state_escape, "escape");
+    } else {
+        err = save_char(p, c);
+    }
+    return err;
+}
+
+static int begin_string(Parser *p, char c){
+    int err = 0;
+    err = Parser_push(p, state_string, "string");
+    if(err) goto exit;
+    new_token(p);
+    p->state->delim = c;
+  exit:
+    return err;
+}
+
+static int end_atom(Parser *p){
+    int err = 0;
+    err = Parser_atom(p);
     if(err) goto exit;
-    newtoken(p);
-    err = savechar(p, c);
+    err = Parser_return(p);
   exit:
     return err;
 }
 
-int state_atom(Parser *p, char c){
+static int state_atom(Parser *p, char c){
     int err = 0;
-    if(at_eof(p)){
+    if(Parser_at_eof(p)){
         err = end_atom(p);
     } else if(is_separator(p, c) ||
               in_space_class(c) ||
@@ -642,258 +723,232 @@ int state_atom(Parser *p, char c){
         if(err) goto exit;
         err = Parser_input_char(p, c);
     } else {
-        err = savechar(p, c);
+        err = save_char(p, c);
     }
   exit:
     return err;
 }
 
-int end_atom(Parser *p){
+static int begin_atom(Parser *p, char c){
     int err = 0;
-    err = do_intern(p);
+    err = Parser_push(p, state_atom, "atom");
     if(err) goto exit;
-    err = Parser_return(p);
+    new_token(p);
+    err = save_char(p, c);
   exit:
     return err;
 }
 
-int state_list(Parser *p, char c){
+static int end_data(Parser *p){
     int err = 0;
-    if(at_eof(p)){
-        parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
-        err = -EINVAL;
-    } else if(c == c_list_close){
-        p->state->val = nrev(p->state->val);
-        err = end_list(p);
-    } else {
-        err = state_start(p, c);
-    }
+    err = Parser_data(p);
+    if(err) goto exit;
+    err = Parser_return(p);
+  exit:
     return err;
-    
-}
-
-int begin_list(Parser *p, char c){
-    return Parser_push(p, state_list, "list");
-}
-
-int end_list(Parser *p){
-    return Parser_return(p);
-}
-
-/** Reset the fields of a parser to initial values.
- *
- * @param z parser
- */
-static void reset(Parser *z){
-  IOStream *error_out = z->error_out;
-  int flags = z->flags;
-  memzero(z, sizeof(Parser));
-  z->buf_n = sizeof(z->buf) - 1;
-  z->buf_i = 0;
-  z->line_no = 1;
-  z->char_no = 0;
-  z->error_out = error_out;
-  z->flags = flags;
-}
-
-/** Set the parser error stream.
- * Parse errors are reported on the the error stream if it is non-null.
- * 
- * @param z parser
- * @param error_out error stream
- */
-void set_error_stream(Parser *z, IOStream *error_out){
-  if(z){
-    z->error_out = error_out;
-  }
 }
 
-/** Get the parser error message for an error code.
- *
- * @param id error code
- * @return error message (empty string if the code is unknown)
- */
-static char *get_message(ParseErrorId id){
-  int i;
-  for(i=0; i<catalog_n; i++){
-    if(id == catalog[i].id){
-      return catalog[i].message;
+static int counted_data(Parser *p, char c){
+    int err = 0;
+    err = save_char(p, c);
+    if(err) goto exit;
+    if(token_len(p) == p->state->count){
+        err = end_data(p);
     }
-  }
-  return "";
-}
-
-/** Get the line number.
- *
- * @param in parser
- */
-int get_line(Parser *in){
-  return in->line_no;
-}
-
-/** Get the column number.
- *
- * @param in parser
- */
-int get_column(Parser *in){
-  return in->char_no;
+  exit:
+    return err;
 }
 
-/** Get the line number the current token started on.
- *
- * @param in parser
- */
-int get_tok_line(Parser *in){
-  return in->tok_begin_line;
+static int counted_data_count(Parser *p, char c){
+    int err = 0;
+    if(c == p->state->delim){
+        new_token(p);
+        p->state->count = p->state->ival;
+        p->state->fn = counted_data;
+    } else if('0' <= c && c <= '9'){
+        p->state->ival *= 10;
+        p->state->ival += c - '0';
+    } else {
+        err = -EINVAL;
+    }
+    return err;
 }
 
-/** Get the column number the current token started on.
- *
- * @param in parser
- */
-int get_tok_column(Parser *in){
-  return in->tok_begin_char;
+static int quoted_data(Parser *p, char c){
+    int err = 0;
+    int count = p->state->count;
+    err = save_char(p, c);
+    if(err) goto exit;
+    // Check that buf is longer than delim and
+    // ends with delim. If so, trim delim off and return.
+    if((token_len(p) >= count) &&
+       !memcmp(p->tok_end - count, p->buf, count)){
+        p->tok_end -= count;
+        end_data(p);
+    }
+  exit:
+    return err;
 }
 
-/** Report a parse error.
- * Does nothing if the error stream is null or there is no error.
- *
- * @param in parser
- */
-static void report_error(Parser *in){
-  if(in->error_out && in->err){
-    char *msg = get_message(in->err);
-    char *tok = peek_token(in);
-    IOStream_print(in->error_out, PARSE_ERR_FMT,
-                  get_tok_line(in), get_tok_column(in), msg);
-    if(tok && tok[0]){
-        IOStream_print(in->error_out, " '%s'", tok);
+static int quoted_data_delim(Parser *p, char c){
+    // Saves the delim in the token buffer.
+    int err = 0;
+    err = save_char(p, c);
+    if(err) goto exit;
+    if(c == p->state->delim){
+        p->state->fn = quoted_data;
+        p->state->count = token_len(p);
+        // Advance the token pointer past the delim.
+        p->tok = p->tok_end;
     }
-    IOStream_print(in->error_out, "\n");
-  }
+  exit:
+    return err;
 }
 
-/** Get the error message for the current parse error code.
- * Does nothing if there is no error.
- *
- * @param in parser
- * @param buf where to place the message
- * @param n maximum number of characters to place in buf
- * @return current error code (zero for no error)
- */
-int parse_error_message(Parser *in, char *buf, int n){
-    if(in->err){
-        char *msg = get_message(in->err);
-        snprintf(buf, n, PARSE_ERR_FMT, get_tok_line(in), get_tok_column(in), msg);
+static int state_data(Parser *p, char c){
+    // Quoted data:
+    // <<delim< anything not containing delimiter<delim<
+    // Where 'delim' is anything not containing '<'.
+    // Counted data:
+    // <*nnn..* N bytes
+    // Where nnn... is N in decimal (
+    int err = 0;
+    switch(c){
+    case c_data_count:
+        p->state->delim = c;
+        p->state->fn = counted_data_count;
+        p->state->ival = 0;
+        new_token(p);
+        break;
+    case c_data_quote:
+        p->state->delim = c;
+        p->state->fn = quoted_data_delim;
+        new_token(p);
+        err = save_char(p, c);
+        break;
+    default:
+        err = Parser_error(p);
+        break;
     }
-    return in->err;
+    return err;
 }
 
-/** Flag an unspecified parse error. All subsequent reads will fail.
- *
- * @param in parser
- */
-void parse_error(Parser *in){
-    parse_error_id(in, PARSE_ERR_INVALID_SYNTAX);
+static int begin_data(Parser *p, char c){
+    int err = 0;
+    err = Parser_push(p, state_data, "data");
+    if(err) goto exit;
+    new_token(p);
+  exit:
+    return err;
 }
 
-/** Flag a parse error. All subsequent reads will fail.
- * Does not change the parser error code if it is already set.
- *
- * @param in parser
- * @param id error code
- */
-void parse_error_id(Parser *in, ParseErrorId id){
-    if(!in->err){
-        in->err = id;
-        report_error(in);
+static int state_list(Parser *p, char c){
+    int err = 0;
+    dprintf(">\n");
+    if(Parser_at_eof(p)){
+        err = Parser_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
+    } else if(c == c_list_close){
+        p->state->val = nrev(p->state->val);
+        err = Parser_return(p);
+    } else {
+        err = state_start(p, c);
     }
+    dprintf("< err=%d\n", err);
+    return err;
+    
 }
 
-/** Test if the parser's error flag is set.
- *
- * @param in parser
- * @return 1 if set, 0 otherwise
- */
-int has_error(Parser *in){
-    return (in->err > 0);
-}
-
-/** Test if the parser is at end of input.
- *
- * @param in parser
- * @return 1 if at EOF, 0 otherwise
- */
-int at_eof(Parser *p){
-    return p->eof;
+static int begin_list(Parser *p, char c){
+    return Parser_push(p, state_list, "list");
 }
 
-#ifdef SXPR_PARSER_MAIN
-/* Stuff for standalone testing. */
-
-#include "file_stream.h"
-#include "string_stream.h"
-
-extern int stringof(Sxpr exp, char **s);
-int child_string(Sxpr exp, Sxpr key, char **s){
+static int state_start(Parser *p, char c){
     int err = 0;
-    Sxpr val = sxpr_child_value(exp, key, ONONE);
-    err = stringof(val, s);
+    dprintf(">\n");
+    if(Parser_at_eof(p)){
+        err = Parser_return(p);
+    } else if(in_space_class(c)){
+        //skip
+    } else if(in_comment_class(c)){
+        begin_comment(p, c);
+    } else if(c == c_list_open){
+        begin_list(p, c);
+    } else if(c == c_list_close){
+        err = Parser_error(p);
+    } else if(in_string_quote_class(c)){
+        begin_string(p, c);
+    } else if(c == c_data_open){
+        begin_data(p, c);
+    } else if(in_printable_class(c)){
+        begin_atom(p, c);
+    } else if(c == 0x04){
+        //ctrl-D, EOT: end-of-text.
+        Parser_input_eof(p);
+    } else {
+        err = Parser_error(p);
+    }
+    dprintf("< err=%d\n", err);
     return err;
 }
 
-extern int intof(Sxpr exp, int *v);
-int child_int(Sxpr exp, Sxpr key, int *v){
+int begin_start(Parser *p, char c){
     int err = 0;
-    Sxpr val = sxpr_child_value(exp, key, ONONE);
-    err = intof(val, v);
+    dprintf(">\n");
+    err = Parser_push(p, state_start, "start");
+    if(err) goto exit;
+    p->start_state = p->state;
+  exit:
+    dprintf("< err=%d\n", err);
     return err;
 }
 
-int eval_vnet(Sxpr exp){
+int Parser_input_char(Parser *p, char c){
     int err = 0;
-    Sxpr oid = intern("id");
-    int id;
-    err = child_int(exp, oid, &id);
-    if(err) goto exit;
-    dprintf("> vnet id=%d\n", id);
- exit:
-    dprintf("< err=%d\n", err);
+    if(Parser_at_eof(p)){
+        //skip;
+    } else {
+        input_char(p, c);
+    }
+    if(!p->state){
+        err = p->begin(p, c);
+        if(err) goto exit;
+    }
+    err = p->state->fn(p, c);
+  exit:
     return err;
 }
 
-int eval_connect(Sxpr exp){
+int Parser_input_eof(Parser *p){
     int err = 0;
-    Sxpr ovif = intern("vif");
-    Sxpr ovnet = intern("vnet");
-    char *vif;
-    int vnet;
-
-    err = child_string(exp, ovif, &vif);
-    if(err) goto exit;
-    err = child_int(exp, ovnet, &vnet);
-    if(err) goto exit;
-    dprintf("> connect vif=%s vnet=%d\n", vif, vnet);
- exit:
-    dprintf("< err=%d\n", err);
+    p->eof = 1;
+    err = Parser_input_char(p, IOSTREAM_EOF);
     return err;
 }
 
-int eval(Sxpr exp){
+int Parser_input(Parser *p, char *buf, int buf_n){
     int err = 0;
-    Sxpr oconnect = intern("connect");
-    Sxpr ovnet = intern("vnet");
-    
-    if(sxpr_elementp(exp, ovnet)){
-        err = eval_vnet(exp);
-    } else if(sxpr_elementp(exp, oconnect)){
-        err = eval_connect(exp);
-    } else {
-        err = -EINVAL;
+    int i = 0;
+    dprintf("> |%s|\n", buf);
+    if(buf_n <= 0){
+        err = Parser_input_eof(p);
+        goto exit;
     }
+    for(i = 0; i < buf_n; i++){
+        err = Parser_input_char(p, buf[i]);
+        if(err) goto exit;
+    }
+  exit:
+    err = (err < 0 ? err : buf_n);
+    dprintf("< err=%d\n", err);
     return err;
 }
 
+#ifdef SXPR_PARSER_MAIN
+/* Stuff for standalone testing. */
+
+#include "file_stream.h"
+//#include "string_stream.h"
+
 /** Main program for testing.
  * Parses input and prints it.
  *
@@ -907,14 +962,16 @@ int main(int argc, char *argv[]){
     char buf[1024];
     int k;
     Sxpr obj;
-    //Sxpr l, x;
     int i = 0;
 
     pin = Parser_new();
-    set_error_stream(pin, iostdout);
+    Parser_set_error_stream(pin, iostdout);
     dprintf("> parse...\n");
     while(1){
-        k = fread(buf, 1, 1, stdin);
+        k = fread(buf, 1, 100, stdin);
+        if(k>=0){
+            buf[k+1] = '\0';
+        }
         err = Parser_input(pin, buf, k);
         while(Parser_ready(pin)){
             obj = Parser_get_val(pin);
@@ -923,12 +980,6 @@ int main(int argc, char *argv[]){
         }
         if(k <= 0) break;
     }
-/*     obj = Parser_get_all(pin); */
-/*     for(l = obj ; CONSP(l); l = CDR(l)){ */
-/*         x = CAR(l); */
-/*         objprint(iostdout, x, 0); printf("\n"); */
-/*         eval(x); */
-/*     } */
     dprintf("> err=%d\n", err);
     return 0;
 }
index 0a3fde55fda1aa7f5895691d200ff765bd77d5df..591ed955727013222bb4f9a59600d1c7ed443721 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
+ * Copyright (C) 2001 - 2005 Mike Wray <mike.wray@hp.com>
  *
  * This library is free software; you can redistribute it and/or modify
  * it under the terms of the GNU Lesser General Public License as
  * Sxpr parsing definitions.
  */
 
-/** Size of a parser input buffer.
- * Tokens read must fit into this size (including trailing null).
+/** Initial size of a parser input buffer.
  */
-#define PARSER_BUF_SIZE 4096
+#define PARSER_BUF_SIZE 512
+
+/** Input buffer size increment (when it's full).
+ */
+#define PARSER_BUF_INCREMENT 512
 
 struct Parser;
 typedef int ParserStateFn(struct Parser *, char c);
@@ -43,13 +46,14 @@ typedef struct ParserState {
     char *name;
 } ParserState;
 
-/** Structure representing an input source for the parser.
- * Can read from any IOStream implementation.
- */
 typedef struct Parser {
+    /** Initial state function. */
+    ParserStateFn *begin;
+    /** Parse value. */
     Sxpr val;
     /** Error reporting stream (null for no reports). */
     IOStream *error_out;
+    /** End-of-file flag, */
     int eof;
     /** Error flag. Non-zero if there has been a read error. */
     int err;
@@ -57,13 +61,11 @@ typedef struct Parser {
     int line_no;
     /** Column number of input (reset on new line). */
     int char_no;
-    /** Lookahead character. */
-    char c;
     /** Buffer for reading tokens. */
-    char buf[PARSER_BUF_SIZE];
-    /** Size of token buffer. */
-    int buf_n;
-    int buf_i;
+    char *buf;
+    char *buf_end;
+    char *tok;
+    char *tok_end;
     /** Line the last token started on. */
     int tok_begin_line;
     /** Character number the last token started on. */
@@ -95,7 +97,7 @@ typedef enum {
  * @param in parser
  * @param flags flags mask
  */
-inline static void parser_flags_raise(Parser *in, int flags){
+inline static void Parser_flags_raise(Parser *in, int flags){
     in->flags |= flags;
 }
 
@@ -104,7 +106,7 @@ inline static void parser_flags_raise(Parser *in, int flags){
  * @param in parser
  * @param flags flags mask
  */
-inline static void parser_flags_lower(Parser *in, int flags){
+inline static void Parser_flags_lower(Parser *in, int flags){
     in->flags &= ~flags;
 }
 
@@ -112,7 +114,7 @@ inline static void parser_flags_lower(Parser *in, int flags){
  *
  * @param in parser
  */
-inline static void parser_flags_clear(Parser *in){
+inline static void Parser_flags_clear(Parser *in){
     in->flags = 0;
 }
 
@@ -121,14 +123,32 @@ extern Parser * Parser_new(void);
 extern int Parser_input(Parser *p, char *buf, int buf_n);
 extern int Parser_input_eof(Parser *p);
 extern int Parser_input_char(Parser *p, char c);
-extern void set_error_stream(Parser *z, IOStream *error_out);
-
-extern int parse_error_message(Parser *in, char *buf, int n);
-extern int has_error(Parser *in);
-extern int at_eof(Parser *in);
-
-int Parser_ready(Parser *p);
-Sxpr Parser_get_val(Parser *p);
-Sxpr Parser_get_all(Parser *p);
+extern void Parser_set_error_stream(Parser *z, IOStream *error_out);
+
+extern int Parser_error_message(Parser *in, char *buf, int n);
+extern int Parser_has_error(Parser *in);
+extern int Parser_at_eof(Parser *in);
+
+extern int Parser_ready(Parser *p);
+extern Sxpr Parser_get_val(Parser *p);
+extern Sxpr Parser_get_all(Parser *p);
+
+/* Internal parser api. */
+void Parser_pop(Parser *p);
+int Parser_push(Parser *p, ParserStateFn *fn, char *name);
+int Parser_return(Parser *p);
+int Parser_at_eof(Parser *p);
+int Parser_error(Parser *in);
+int Parser_set_value(Parser *p, Sxpr val);
+int Parser_intern(Parser *p);
+int Parser_string(Parser *p);
+int Parser_data(Parser *p);
+int Parser_uint(Parser *p);
+
+char *peek_token(Parser *p);
+char *copy_token(Parser *p);
+void new_token(Parser *p);
+int save_char(Parser *p, char c);
+int token_len(Parser *p);
 
 #endif /* ! _XUTIL_SXPR_PARSER_H_ */
index 13a90dfd7d77122942b29884327f7cca1dbf9a99..22a8ae3688ab16e0287d5cc2989e45556c224bba 100644 (file)
@@ -49,6 +49,27 @@ inline static const char * convert_set_base(const char *s, int *base){
     return s;
 }
 
+/** Set the sign to use for converting a string to a number.
+ * Value is 1 for positive, -1 for negative.
+ *
+ * @param s input string
+ * @param sign where to put the sign
+ * @return rest of s to parse as a number
+ */
+inline static const char * convert_set_sign(const char *s, int *sign){
+    *sign = 1;
+    if(s){
+        if(*s == '+'){
+            *sign = 1;
+            s++;
+        } else if (*s == '-'){
+            *sign = -1;
+            s++;
+        }
+    }
+    return s;
+}
+
 /** Get the numerical value of a digit in the given base.
  *
  * @param c digit character
@@ -103,6 +124,40 @@ int convert_atoul(const char *str, unsigned long *val){
     return err;
 }
 
+/** Convert a string to a long by parsing it as a number.
+ * Will accept hex or decimal in usual C syntax.
+ *
+ * @param str input string
+ * @param val where to put the result
+ * @return 0 if converted OK, negative otherwise
+ */
+int convert_atol(const char *str, long *val){
+    int err = 0;
+    unsigned long v = 0;
+    int base, sign = 1;
+    const char *s = str;
+
+    if(!s) {
+        err = -EINVAL;
+        goto exit;
+    }
+    s = convert_set_sign(s, &sign);
+    s = convert_set_base(s, &base);
+    for( ; !err && *s; s++){
+        int digit = convert_get_digit(*s, base);
+        if(digit<0){
+            err = -EINVAL;
+            goto exit;
+        }
+        v *= base;
+        v += digit;
+    } 
+    if(sign < 0) v = -v;
+  exit:
+    *val = (err ? 0 : v);
+    return err;
+}
+
 /** Combine a directory path with a relative path to produce
  * a new path.
  *
index ea604011683a119238c42926995c59b547d576d0..88d9d8db6173ae9ee224a66091d8c6480d5c52a8 100644 (file)
@@ -86,6 +86,7 @@ static inline size_t strnlen(const char *s, size_t n){
 /*============================================================================*/
 
 extern int convert_atoul(const char *s, unsigned long *v);
+extern int convert_atol(const char *s, long *v);
 extern int path_concat(char *s, char *t, char **val);
 
 #endif /* !_XUTIL_SYS_STRING_H_ */
index 557c18ecdd99e65f7183aa8d3ffe5a6db655b4fc..3709f17eddb0f15ce72c483f52301367335cf010 100644 (file)
@@ -60,7 +60,6 @@ class Daemon:
             if not pm: continue
             xm = xendre.match(pm.group('cmd'))
             if not xm: continue
-            #print 'pid=', pm.group('pid'), 'cmd=', pm.group('cmd')
             pids.append(int(pm.group('pid')))
         return pids
 
@@ -313,7 +312,7 @@ class Daemon:
             os.setuid(pwd.getpwnam(XEND_USER)[2])
             return 0
         except KeyError, error:
-            print "Error: no such user '%s'" % XEND_USER
+            print >>sys.stderr, "Error: no such user '%s'" % XEND_USER
             return 1
 
     def stop(self):
@@ -328,7 +327,6 @@ class Daemon:
             self.listenChannels()
             servers = SrvServer.create()
             self.daemonize()
-            print 'running serverthread...'
             servers.start()
         except Exception, ex:
             print >>sys.stderr, 'Exception starting xend:', ex
@@ -342,14 +340,12 @@ class Daemon:
 
     def listenChannels(self):
         def virqReceived(virq):
-            print 'virqReceived>', virq
             eserver.inject('xend.virq', virq)
 
         self.channelF.setVirqHandler(virqReceived)
         self.channelF.start()
 
     def exit(self, rc=0):
-        #reactor.disconnectAll()
         if self.channelF:
             self.channelF.stop()
         # Calling sys.exit() raises a SystemExit exception, which only
index ce76c149b03985d84ffc0a1fb6a9bf64ff79ff00..e0096d2d95987b1146aa8b93dac184796b451fd4 100644 (file)
@@ -3,17 +3,13 @@ import StringIO
 
 from xen.web import reactor, protocol
 
-from xen.lowlevel import xu
-
 from xen.xend import sxp
 from xen.xend import PrettyPrint
-from xen.xend import EventServer
-eserver = EventServer.instance()
+from xen.xend import EventServer; eserver = EventServer.instance()
 from xen.xend.XendError import XendError
-
 from xen.xend import XendRoot; xroot = XendRoot.instance()
 
-DEBUG = 1
+DEBUG = 0
 
 class EventProtocol(protocol.Protocol):
     """Asynchronous handler for a connected event socket.
@@ -30,7 +26,7 @@ class EventProtocol(protocol.Protocol):
         self.pretty = 0
 
         # For debugging subscribe to everything and make output pretty.
-        self.subscribe(['*'])
+        #self.subscribe(['*'])
         self.pretty = 1
 
     def dataReceived(self, data):
@@ -45,10 +41,7 @@ class EventProtocol(protocol.Protocol):
         except SystemExit:
             raise
         except:
-            if DEBUG:
-                raise
-            else:
-                self.send_error()
+            self.send_error()
 
     def loseConnection(self):
         if self.transport:
@@ -73,7 +66,11 @@ class EventProtocol(protocol.Protocol):
             return 0
 
     def send_result(self, res):
-        return self.send_reply(['ok', res])
+        if res is None:
+            resp = ['ok']
+        else:
+            resp = ['ok', res]
+        return self.send_reply(resp)
 
     def send_error(self):
         (extype, exval) = sys.exc_info()[:2]
@@ -129,7 +126,6 @@ class EventProtocol(protocol.Protocol):
 
     def op_pretty(self, name, req):
         self.pretty = 1
-        return ['ok']
 
     def op_console_disconnect(self, name, req):
         id = sxp.child_value(req, 'id')
@@ -137,7 +133,6 @@ class EventProtocol(protocol.Protocol):
             raise XendError('Missing console id')
         id = int(id)
         self.daemon.console_disconnect(id)
-        return ['ok']
 
     def op_info(self, name, req):
         val = ['info']
@@ -151,13 +146,11 @@ class EventProtocol(protocol.Protocol):
         # (sys.subscribe event*)
         # Subscribe to the events:
         self.subscribe(v[1:])
-        return ['ok']
 
     def op_sys_inject(self, name, v):
         # (sys.inject event)
         event = v[1]
         eserver.inject(sxp.name(event), event)
-        return ['ok']
 
     def op_trace(self, name, v):
         mode = (v[1] == 'on')
@@ -181,6 +174,27 @@ class EventProtocol(protocol.Protocol):
         import controller
         controller.DEBUG = (mode == 'on')
 
+    def op_domain_ls(self, name, v):
+        xd = xroot.get_component("xen.xend.XendDomain")
+        return xd.domain_ls()
+
+    def op_domain_configure(self, name, v):
+        domid = sxp.child_value(v, "dom")
+        config = sxp.child_value(v, "config")
+        if domid is None:
+            raise XendError("missing domain id")
+        if config is None:
+            raise XendError("missing domain config")
+        xd = xroot.get_component("xen.xend.XendDomain")
+        xd.domain_configure(domid, config)
+
+    def op_domain_unpause(self, name, v):
+        domid = sxp.child_value(v, "dom")
+        if domid is None:
+            raise XendError("missing domain id")
+        xd = xroot.get_component("xen.xend.XendDomain")
+        xd.domain_unpause(domid)
+
 class EventFactory(protocol.ServerFactory):
     """Asynchronous handler for the event server socket.
     """
index 3bbfe4d5d6c5f610595f0f79ea556f8b9a4cf776..a3f13a4fd4cf0b30ce7deef2112c007c06f9a740 100644 (file)
@@ -6,6 +6,7 @@ UTIL_LIB = libutil.a
 UTIL_LIB_SRC =
 UTIL_LIB_SRC += allocate.c
 UTIL_LIB_SRC += enum.c
+UTIL_LIB_SRC += fd_stream.c
 UTIL_LIB_SRC += file_stream.c
 UTIL_LIB_SRC += gzip_stream.c
 UTIL_LIB_SRC += hash_table.c
@@ -19,7 +20,7 @@ UTIL_LIB_SRC += sxpr_parser.c
 UTIL_LIB_SRC += sys_net.c
 UTIL_LIB_SRC += sys_string.c
 #UTIL_LIB_SRC += util.c
-UTIL_LIB_SRC += xdr.c
+#UTIL_LIB_SRC += xdr.c
 
 #----------------------------------------------------------------------------
 # Xfrd.
index fb6f2ae244a27bdcaf9cc1ba5194ed4ba1383056..949c6f915ac80a38b974f82343a89422053d62bc 100644 (file)
@@ -26,18 +26,11 @@ UTIL_LIB_OBJ = $(UTIL_LIB_SRC:.c=.o)
 XFRD_PROG_OBJ = $(XFRD_PROG_SRC:.c=.o)
 XFRD_PROG_OBJ += $(UTIL_LIB)
 
-# Flag controlling whether to use stubs.
-# Define to use stubs, undefine to use the real Xen functions.
-#CPPFLAGS += -D _XEN_XFR_STUB_
-
-ifeq ($(SXPR_DEBUG),1)
-CPPFLAGS += -D _XEN_XFR_STUB_ -D SXPR_PARSER_MAIN
-endif
-
 CC := gcc
 
 CFLAGS += -Wall -Werror -O3 -fno-strict-aliasing
 CFLAGS += $(INCLUDES)
+
 # Make gcc generate dependencies.
 CFLAGS += -Wp,-MD,.$(@F).d
 PROG_DEP = .*.d
@@ -55,12 +48,6 @@ XFRD_LIBS += -L $(XEN_LIBXUTIL) -lxutil
 # zlib library.
 XFRD_LIBS += -lz
 
-CURL_FLAGS = $(shell curl-config --cflags)
-CURL_LIBS  = $(shell curl-config --libs)
-CFLAGS     += $(CURL_FLAGS)
-# libcurl libraries.
-XFRD_LIBS += $(CURL_LIBS)
-
 #$(warning XFRD_LIBS = $(XFRD_LIBS))
 
 all: build
index 36f2ca8475150111c5ac21cfc55e05eb66dfb81a..7b493cdcfad712d84981e6ea5d808df5e9454a6f 100644 (file)
@@ -171,7 +171,7 @@ int Conn_sxpr(Conn *conn, Sxpr *sxpr){
     dprintf(">\n");
     if(!conn->parser){
         conn->parser = Parser_new();
-        set_error_stream(conn->parser, iostdout);
+        Parser_set_error_stream(conn->parser, iostdout);
     }
     while(!err && c >= 0 && !Parser_ready(conn->parser)){
         c = IOStream_getc(conn->in);
index fb72f7703bf5ad2d8aae4791580c62a090a1e9a7..b50b5c79537aa590a6c6e7d892cc993139f35ca1 100644 (file)
@@ -475,7 +475,6 @@ static int lzi_close(IOStream *io){
  */
 static void lzi_free(IOStream *s){
     LZIState *state = lzi_state(s);
-    IOStream_free(state->io);
     LZIState_free(state);
     s->data = NULL;
 }
@@ -525,8 +524,8 @@ IOStream *lzi_stream_fdopen(int fd, const char *mode){
     err = 0;
   exit:
     if(err){
-        IOStream_free(io);
-        IOStream_free(zio);
+        IOStream_close(io);
+        IOStream_close(zio);
         zio = NULL;
     }
     return zio;
index 8a374eba9763ed831b3f10e536225abd31a622de..9f9d1f15a6d3fc6e50bbf5838e9ae900679c40c7 100644 (file)
@@ -1,17 +1,18 @@
 #include <unistd.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <sys/socket.h>
+#include <sys/un.h>
 
-#ifdef _XEN_XFR_STUB_
-typedef unsigned long u32;
-#else
 #include "xc.h"
 #include "xc_io.h"
-#endif
+
+#include "sxpr.h"
+#include "sxpr_parser.h"
+#include "file_stream.h"
+#include "fd_stream.h"
 
 #include "xen_domain.h"
-#include "marshal.h"
-#include "xdr.h"
 #include "xfrd.h"
 
 #define MODULE_NAME "XFRD"
@@ -33,7 +34,6 @@ int domain_configure(void *data, u32 dom, char *vmconfig, int vmconfig_n){
     return xen_domain_configure(dom, vmconfig, vmconfig_n);
 }
 
-#ifndef _XEN_XFR_STUB_
 static int xc_handle = 0;
 
 int xcinit(void){
@@ -50,7 +50,6 @@ void xcfini(void){
         xc_handle = 0;
     }
 }
-#endif   
 
 /** Write domain state.
  *
@@ -62,31 +61,6 @@ int xen_domain_snd(Conn *xend, IOStream *io,
                    char *vmconfig, int vmconfig_n,
                    int live, int resource){
     int err = 0;
-#ifdef _XEN_XFR_STUB_
-    char buf[1024];
-    int n, k, d, buf_n;
-    dprintf("> dom=%d\n", dom);
-    err = marshal_uint32(io, dom);
-    if(err) goto exit;
-    err = marshal_string(io, vmconfig, vmconfig_n);
-    if(err) goto exit;
-    n = 32 * 1024 * 1024;
-    n = 32 * 1024;
-    buf_n = sizeof(buf);
-    err = marshal_uint32(io, n);
-    for(k = 0; k < n; k += d){
-        d = n - k;
-        if(d > buf_n) d = buf_n;
-        err = marshal_bytes(io, buf, d);
-        if(err) goto exit;
-        dprintf("> k=%d n=%d\n", k, n);
-    }
-    
-    dom = 99;
-    err = domain_suspend(xend, dom);
-    IOStream_close(io);
-  exit:
-#else 
     XcIOContext _ioctxt = {}, *ioctxt = &_ioctxt;
     ioctxt->domain = dom;
     ioctxt->io = io;
@@ -101,7 +75,6 @@ int xen_domain_snd(Conn *xend, IOStream *io,
     }
     ioctxt->resource = resource;
     err = xc_linux_save(xcinit(), ioctxt);
-#endif   
     dprintf("< err=%d\n", err);
     return err;
 }
@@ -114,25 +87,6 @@ int xen_domain_rcv(IOStream *io,
                    char **vmconfig, int *vmconfig_n,
                    int *configured){
     int err = 0;
-#ifdef _XEN_XFR_STUB_
-    char buf[1024];
-    int n, k, d, buf_n;
-    dprintf(">\n");
-    err = unmarshal_uint32(io, dom);
-    if(err) goto exit;
-    err = unmarshal_new_string(io, vmconfig, vmconfig_n);
-    if(err) goto exit;
-    err = unmarshal_uint32(io, &n);
-    buf_n = sizeof(buf);
-    for(k = 0; k < n; k += d){
-        d = n - k;
-        if(d > buf_n) d = buf_n;
-        err = unmarshal_bytes(io, buf, d);
-        if(err) goto exit;
-        dprintf("> k=%d n=%d\n", k, n);
-    }
-  exit:
-#else    
     XcIOContext _ioctxt = {}, *ioctxt = &_ioctxt;
     dprintf(">\n");
     ioctxt->io = io;
@@ -147,137 +101,182 @@ int xen_domain_rcv(IOStream *io,
     *vmconfig = ioctxt->vmconfig;
     *vmconfig_n = ioctxt->vmconfig_n;
     *configured = (ioctxt->flags & XCFLAGS_CONFIGURE);
-#endif   
     dprintf("< err=%d\n", err);
     return err;
 }
 
-#include <curl/curl.h>
-#include "http.h"
+typedef struct xend {
+    int fd;
+    IOStream *io;
+    Parser *parser;
+    int seeneof;
+} Xend;
 
-/** Flag indicating whether we need to initialize libcurl. 
- */
-static int do_curl_global_init = 1;
+char *xend_server_addr(void){
+    char * val = getenv("XEND_EVENT_ADDR");
+    return (val ? val : "/var/lib/xend/event-socket");
+}
 
-/** Get a curl handle, initializing libcurl if needed.
- *
- * @return curl handle
+/** Open a unix-domain socket to the xend server.
  */
-static CURL *curlinit(void){
-    if(do_curl_global_init){
-        do_curl_global_init = 0;
-        // Stop libcurl using the proxy. There's a curl option to
-        // set the proxy - but no option to defeat it.
-        unsetenv("http_proxy");
-        curl_global_init(CURL_GLOBAL_ALL);
+int xend_open_fd(void){
+    struct sockaddr_un addr_un = { .sun_family = AF_UNIX };
+    struct sockaddr *addr = (struct sockaddr*)&addr_un;
+    int addr_n = sizeof(addr_un);
+    int err = 0;
+
+    int fd = socket(AF_UNIX, SOCK_STREAM, 0);
+    if(fd < 0){
+        err = -errno;
+        perror("socket");
+        goto exit;
     }
-    return curl_easy_init();
+    strcpy(addr_un.sun_path, xend_server_addr());
+    if(connect(fd, addr, addr_n) < 0){
+        err = -errno;
+        perror("connect");
+        goto exit;
+    }
+  exit:
+    if(err && (fd >= 0)){
+        close(fd);
+    }
+    
+    return (err ? err : fd);
 }
 
-/** Curl debug function.
- */
-int curldebug(CURL *curl, curl_infotype ty, char *buf, int buf_n, void *data){
-    // printf("%*s\n", buf_n, buf); /* Does not compile correctly on non 32bit platforms */
-    fwrite(data, buf_n, 1, stdout);
-    printf("\n");
-    return 0;
+/** Close a connection to the server.
+ *
+  * @param xend connection
+*/
+void xend_close(Xend *xend){
+    if(!xend) return;
+    close(xend->fd);
+    Parser_free(xend->parser);
 }
 
-/** Setup a curl handle with a url.
- * Creates the url by formatting 'fmt' and the remaining arguments.
+/** Open a connection to the server.
  *
- * @param pcurl return parameter for the curl handle
- * @param url url buffer
- * @param url_n size of url
- * @param fmt url format string, followed by parameters
- * @return 0 on success, error code otherwise
+ * @param xend result parameter for the connection
+ * @return 0 on success, negative error code otherwise
  */
-static int curlsetup(CURL **pcurl, struct curl_slist **pheaders, char *url, int url_n, char *fmt, ...){
+int xend_open(Xend **xend){
     int err = 0;
-    va_list args;
-    CURL *curl = NULL;
-    struct curl_slist *headers = NULL;
-    int n = 0;
+    Xend *val = ALLOCATE(Xend);
 
-    curl = curlinit();
-    if(!curl){
-        eprintf("> Could not init libcurl\n");
-        err = -ENOMEM;
-        goto exit;
-    }
-    url_n -= 1;
-    va_start(args, fmt);
-    n = vsnprintf(url, url_n, fmt, args);
-    va_end(args);
-    if(n <= 0 || n >= url_n){
-        err = -ENOMEM;
-        eprintf("> Out of memory in url\n");
+    val->fd = xend_open_fd();
+
+    if(val->fd < 0){
+        err = val->fd;
         goto exit;
     }
-    dprintf("> url=%s\n", url);
-#if DEBUG
-    // Verbose.
-    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
-    // Call the debug function on data received.
-    curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, curldebug);
-#else
-    // No progress meter.
-    curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
-    // Completely quiet.
-    curl_easy_setopt(curl, CURLOPT_MUTE, 1);
-#endif
-    // Set the URL.
-    curl_easy_setopt(curl, CURLOPT_URL, url);
-
-    headers = curl_slist_append(headers, "Expect:");
-    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
-    
+    val->io = fd_stream_new(val->fd);
+    val->parser = Parser_new();
   exit:
-    if(err && curl){
-        curl_easy_cleanup(curl);
-        curl = NULL;
-    }
-    *pcurl = curl;
-    if (pheaders)
-       *pheaders = headers;
+    if(err) xend_close(val);
+    *xend = (err ? NULL : val);
     return err;
 }
 
-static void curlcleanup(CURL **pcurl, struct curl_slist **pheaders){
-    if (*pcurl)
-       curl_easy_cleanup(*pcurl);
-    if (*pheaders)
-       curl_slist_free_all(*pheaders);
-    *pcurl = NULL;
-    *pheaders = NULL;
+/** Read a response from a server connection.
+ */
+int xend_read_resp(Xend *xend, Sxpr *resp){
+    int err = 0;
+    Sxpr val = ONONE;
+    char buf[1024];
+    int buf_n = sizeof(buf), n;
+
+    for( ; ; ){
+        if(Parser_ready(xend->parser)){
+            val = Parser_get_val(xend->parser);
+            goto exit;
+        }
+        if(xend->seeneof){
+            err = -EIO;
+            goto exit;
+        }
+        memset(buf, 0, buf_n);
+        n = IOStream_read(xend->io, buf, 100);
+        if(n <= 0){
+            xend->seeneof = 1;
+            err = Parser_input_eof(xend->parser);
+        } else {
+            err = Parser_input(xend->parser, buf, n);
+        }
+    }
+  exit:
+    *resp = (err < 0 ? ONONE : val);
+    return err;
 }
-/** Make the http request stored in the curl handle and get
- *  the result code from the curl code and the http return code.
+
+/** Read a response from a server connection and decode the value.
  *
- * @param curl curl handle
- * @return 0 for success, error code otherwise
+ * @param xend server connection
+ * @param resp result parameter for the response value
+ * @return 0 on success, negative error code otherwise
  */
-int curlresult(CURL *curl){
+int xend_read(Xend *xend, Sxpr *resp){
     int err = 0;
-    CURLcode curlcode = 0;
-    long httpcode = 0;
+    Sxpr val = ONONE;
 
-    curlcode = curl_easy_perform(curl);
-    if(curlcode){
-        eprintf("> curlcode=%d\n", curlcode);
-        err = -EINVAL;
-        goto exit;
-    }
-    curl_easy_getinfo(curl, CURLINFO_HTTP_CODE, &httpcode);
-    if(httpcode != HTTP_OK){
-        eprintf("> httpcode=%d\n", (int)httpcode);
-        err = -EINVAL;
-        goto exit;
+    dprintf(">\n");
+    for( ; ; ){
+        err = xend_read_resp(xend, &val);
+        if(err < 0) goto exit;
+        
+        if(sxpr_is(sxpr_name(val), "event")){
+            // We don't care about events, try again.
+            err = 0;
+            continue;
+        } else if(sxpr_is(sxpr_name(val), "err")){
+            eprintf("> "); objprint(iostderr, val, 0); fprintf(stderr, "\n");
+            err = -EINVAL;
+            break;
+        } else {
+            err = 0;
+            val = sxpr_child0(val, ONULL);
+            break;
+        }
     }
+#ifdef DEBUG
+    dprintf("> OK ");
+    objprint(iostdout, val, 0);
+    printf("\n");
+#endif
   exit:
+    if(resp){
+        *resp = (err < 0 ? ONONE : val);
+    }
+    dprintf("> err=%d\n", err);
     return err;
 }
 
+/** Send a request to the server and return the result value in resp.
+ *
+ * @param xend server connection
+ * @param resp result parameter for the response value
+ * @param format request format followed by args to print
+ * @return 0 on success, negative error code otherwise
+ */
+int xend_call(Xend *xend, Sxpr *resp, char *format, ...){
+    va_list args;
+    int err;
+    
+    dprintf("> ");
+    va_start(args, format);
+#ifdef DEBUG
+    vprintf(format, args); printf("\n");
+#endif
+    err = IOStream_vprint(xend->io, format, args);
+    va_end(args);
+    if(err < 0) goto exit;
+    IOStream_flush(xend->io);
+    err = xend_read(xend, resp);
+  exit:
+    dprintf("> err=%d\n", err);
+    return (err < 0 ? err : 0);
+}
+
 /** Get xend to list domains.
  * We use this to force xend to refresh its domain list.
  *
@@ -285,18 +284,12 @@ int curlresult(CURL *curl){
  */
 int xen_domain_ls(void){
     int err = 0;
-    CURL *curl = NULL;
-    struct curl_slist *headers = NULL;
-    char url[128] = {};
-    int url_n = sizeof(url);
-
-    dprintf(">\n");
-    err = curlsetup(&curl, &headers, url, url_n, "http://localhost:%d/xend/domain", XEND_PORT);
+    Xend *xend = NULL;
+    err = xend_open(&xend);
     if(err) goto exit;
-    err = curlresult(curl);
+    err = xend_call(xend, NULL, "(domain.ls)");
   exit:
-    curlcleanup(&curl, &headers);
-    dprintf("< err=%d\n", err);
+    xend_close(xend);
     return err;
 }
 
@@ -309,49 +302,18 @@ int xen_domain_ls(void){
  */
 int xen_domain_configure(uint32_t dom, char *vmconfig, int vmconfig_n){
     int err = 0;
-    CURL *curl = NULL;
-    struct curl_slist *headers = NULL;
-    char url[128] = {};
-    int url_n = sizeof(url);
-    struct curl_httppost *form = NULL, *last = NULL;
-    CURLFORMcode formcode = 0;
-
+    Xend *xend = NULL;
     dprintf("> dom=%u\n", dom);
     // List domains so that xend will update its domain list and notice the new domain.
     xen_domain_ls();
-
-    err = curlsetup(&curl, &headers, url, url_n, "http://localhost:%d/xend/domain/%u", XEND_PORT, dom);
+    // Now configure it.
+    err = xend_open(&xend);
     if(err) goto exit;
-
-    // Config field - set from vmconfig.
-    formcode = curl_formadd(&form, &last,
-                            CURLFORM_COPYNAME,     "config",
-                            CURLFORM_BUFFER,       "config",
-                            CURLFORM_BUFFERPTR,    vmconfig,
-                            CURLFORM_BUFFERLENGTH, vmconfig_n,
-                            CURLFORM_CONTENTTYPE,  "application/octet-stream",
-                            CURLFORM_END);
-    if(formcode){
-        eprintf("> Error adding config field.\n");
-        goto exit;
-    }
-    // Op field.
-    formcode = curl_formadd(&form, &last,
-                            CURLFORM_COPYNAME,     "op",
-                            CURLFORM_COPYCONTENTS, "configure",
-                            CURLFORM_END);
-    if(formcode){
-        eprintf("> Error adding op field.\n");
-        err = -EINVAL;
-        goto exit;
-    }
-    // POST the form.
-    curl_easy_setopt(curl, CURLOPT_HTTPPOST, form);
-    err = curlresult(curl);
+    err = xend_call(xend, NULL, "(domain.configure (dom %d) (config %*s))",
+                    dom, vmconfig_n, vmconfig);
   exit:
-    curlcleanup(&curl, &headers);
-    if(form) curl_formfree(form);
     dprintf("< err=%d\n", err);
+    xend_close(xend);
     return err;
 }
 
@@ -362,34 +324,11 @@ int xen_domain_configure(uint32_t dom, char *vmconfig, int vmconfig_n){
  */
 int xen_domain_unpause(uint32_t dom){
     int err = 0;
-    CURL *curl = NULL;
-    struct curl_slist *headers = NULL;
-    char url[128] = {};
-    int url_n = sizeof(url);
-    struct curl_httppost *form = NULL, *last = NULL;
-    CURLFORMcode formcode = 0;
-
-    dprintf("> dom=%u\n", dom);
-
-    err = curlsetup(&curl, &headers, url, url_n, "http://localhost:%d/xend/domain/%u", XEND_PORT, dom);
+    Xend *xend = NULL;
+    err = xend_open(&xend);
     if(err) goto exit;
-
-    // Op field.
-    formcode = curl_formadd(&form, &last,
-                            CURLFORM_COPYNAME,     "op",
-                            CURLFORM_COPYCONTENTS, "unpause",
-                            CURLFORM_END);
-    if(formcode){
-        eprintf("> Error adding op field.\n");
-        err = -EINVAL;
-        goto exit;
-    }
-    // POST the form.
-    curl_easy_setopt(curl, CURLOPT_HTTPPOST, form);
-    err = curlresult(curl);
+    err = xend_call(xend, NULL, "(domain.unpause (dom %d))", dom);
   exit:
-    curlcleanup(&curl, &headers);
-    if(form) curl_formfree(form);
-    dprintf("< err=%d\n", err);
+    xend_close(xend);
     return err;
 }
index 89353e0e3b24971370b1bd603a2fe94f390efb4b..2379b045c7801d99708011f8a5fd853f143d8cd9 100644 (file)
@@ -188,7 +188,6 @@ enum {
     XFR_MAX
 };
 
-#ifndef SXPR_PARSER_MAIN
 /** Short options. Options followed by ':' take an argument. */
 static char *short_opts = (char[]){
     OPT_PORT,     ':',
@@ -213,7 +212,6 @@ static Args _args = {};
 
 /** Xfrd arguments. */
 static Args *args = &_args;
-#endif
 
 /** Initialize an array element for a constant to its string name. */
 #define VALDEF(val) { val, #val }
@@ -782,7 +780,6 @@ int xfr_save(Args *args, XfrState *state, Conn *xend, char *file){
   exit:
     if(io){
         IOStream_close(io);
-        IOStream_free(io);
     }
     if(err){
         unlink(file);
@@ -798,7 +795,7 @@ int xfr_save(Args *args, XfrState *state, Conn *xend, char *file){
 int xfr_restore(Args *args, XfrState *state, Conn *xend, char *file){
     int err = 0;
     IOStream *io = NULL;
-    int configured=0;
+    int configured = 0;
 
     dprintf("> file=%s\n", file);
     io = gzip_stream_fopen(file, "rb");
@@ -820,7 +817,6 @@ int xfr_restore(Args *args, XfrState *state, Conn *xend, char *file){
   exit:
     if(io){
         IOStream_close(io);
-        IOStream_free(io);
     }
     if(err){
         xfr_error(xend, err);
@@ -1215,7 +1211,6 @@ int xfrd_main(Args *args){
     return err;
 }
 
-#ifndef SXPR_PARSER_MAIN
 /** Parse command-line arguments and call the xfrd main program.
  *
  * @param arg argument count
@@ -1271,4 +1266,3 @@ int main(int argc, char *argv[]){
     }
     return (err ? 1 : 0);
 }
-#endif